false
true
0

Contract Address Details

0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6

Contract Name
PiteasRouter
Creator
0x36900b–9aa6a4 at 0xd48a2c–90d02c
Balance
1,618,769.812412676561517978 PLS ( )
Tokens
Fetching tokens...
Transactions
2,850,859 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
25912387
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
PiteasRouter




Optimization enabled
false
Compiler version
v0.8.18+commit.87f61d96




EVM Version
default




Verified at
2023-07-07T21:39:49.445468Z

Contract source code

// File: @openzeppelin/contracts/utils/Context.sol


// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

// File: @openzeppelin/contracts/access/Ownable.sol


// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;


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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

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

// File: @openzeppelin/contracts/utils/math/SafeMath.sol


// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

// File: @openzeppelin/contracts/token/ERC20/IERC20.sol


// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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 amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` 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 amount) external returns (bool);
}

// File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol


// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// File: @openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol


// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

// EIP-2612 is Final as of 2022-11-01. This file is deprecated.


// File: verified-sources/0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6/sources/deployed-version-final/interfaces/IDaiLikePermit.sol



pragma solidity ^0.8.0;

interface IDaiLikePermit {
    function permit(
        address holder,
        address spender,
        uint256 nonce,
        uint256 expiry,
        bool allowed,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

// File: verified-sources/0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6/sources/deployed-version-final/interfaces/IPermit2.sol



pragma solidity ^0.8.0;

interface IPermit2 {
    struct PermitDetails {
        // ERC20 token address
        address token;
        // the maximum amount allowed to spend
        uint160 amount;
        // timestamp at which a spender's token allowances become invalid
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }
    /// @notice The permit message signed for a single token allownce
    struct PermitSingle {
        // the permit data for a single token alownce
        PermitDetails details;
        // address permissioned on the allowed tokens
        address spender;
        // deadline on the permit signature
        uint256 sigDeadline;
    }
    /// @notice Packed allowance
    struct PackedAllowance {
        // amount allowed
        uint160 amount;
        // permission expiry
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }

    function transferFrom(address user, address spender, uint160 amount, address token) external;

    function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;

    function allowance(address user, address token, address spender) external view returns (PackedAllowance memory);
}

// File: verified-sources/0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6/sources/deployed-version-final/interfaces/IWETH.sol



pragma solidity ^0.8.0;


interface IWETH is IERC20 {
    event Deposit(address indexed dst, uint wad);

    event Withdrawal(address indexed src, uint wad);

    function deposit() external payable;

    function withdraw(uint256 amount) external;
}

// File: verified-sources/0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6/sources/deployed-version-final/libraries/RevertReasonForwarder.sol



pragma solidity ^0.8.0;

/// @title Revert reason forwarder.
library RevertReasonForwarder {
    /// @dev Forwards latest externall call revert.
    function reRevert() internal pure {
        // bubble up revert reason from latest external call
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            let ptr := mload(0x40)
            returndatacopy(ptr, 0, returndatasize())
            revert(ptr, returndatasize())
        }
    }
}

// File: verified-sources/0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6/sources/deployed-version-final/libraries/SafeERC20.sol



pragma solidity ^0.8.0;







/**
 * @title Implements efficient safe methods for ERC20 interface.
 * @notice Compared to the standard ERC20, this implementation offers several enhancements:
 * 1. more gas-efficient, providing significant savings in transaction costs.
 * 2. support for different permit implementations
 * 3. forceApprove functionality
 * 4. support for WETH deposit and withdraw
 */
library SafeERC20 {
    error SafeTransferFailed();
    error SafeTransferFromFailed();
    error ForceApproveFailed();
    error SafeIncreaseAllowanceFailed();
    error SafeDecreaseAllowanceFailed();
    error SafePermitBadLength();
    error Permit2TransferAmountTooHigh();

    // Uniswap Permit2 address
    address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
    bytes4 private constant _PERMIT_LENGTH_ERROR = 0x68275857;  // SafePermitBadLength.selector
    uint256 private constant _RAW_CALL_GAS_LIMIT = 5000;

    /**
     * @notice Fetches the balance of a specific ERC20 token held by an account.
     * Consumes less gas then regular `ERC20.balanceOf`.
     * @param token The IERC20 token contract for which the balance will be fetched.
     * @param account The address of the account whose token balance will be fetched.
     * @return tokenBalance The balance of the specified ERC20 token held by the account.
     */
    function safeBalanceOf(
        IERC20 token,
        address account
    ) internal view returns(uint256 tokenBalance) {
        bytes4 selector = IERC20.balanceOf.selector;
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            mstore(0x00, selector)
            mstore(0x04, account)
            let success := staticcall(gas(), token, 0x00, 0x24, 0x00, 0x20)
            tokenBalance := mload(0)

            if or(iszero(success), lt(returndatasize(), 0x20)) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
        }
    }

    /**
     * @notice Attempts to safely transfer tokens from one address to another.
     * @dev If permit2 is true, uses the Permit2 standard; otherwise uses the standard ERC20 transferFrom. 
     * Either requires `true` in return data, or requires target to be smart-contract and empty return data.
     * @param token The IERC20 token contract from which the tokens will be transferred.
     * @param from The address from which the tokens will be transferred.
     * @param to The address to which the tokens will be transferred.
     * @param amount The amount of tokens to transfer.
     * @param permit2 If true, uses the Permit2 standard for the transfer; otherwise uses the standard ERC20 transferFrom.
     */
    function safeTransferFromUniversal(
        IERC20 token,
        address from,
        address to,
        uint256 amount,
        bool permit2
    ) internal {
        if (permit2) {
            safeTransferFromPermit2(token, from, to, amount);
        } else {
            safeTransferFrom(token, from, to, amount);
        }
    }

    /**
     * @notice Attempts to safely transfer tokens from one address to another using the ERC20 standard.
     * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
     * @param token The IERC20 token contract from which the tokens will be transferred.
     * @param from The address from which the tokens will be transferred.
     * @param to The address to which the tokens will be transferred.
     * @param amount The amount of tokens to transfer.
     */
    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bytes4 selector = token.transferFrom.selector;
        bool success;
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            let data := mload(0x40)

            mstore(data, selector)
            mstore(add(data, 0x04), from)
            mstore(add(data, 0x24), to)
            mstore(add(data, 0x44), amount)
            success := call(gas(), token, 0, data, 100, 0x0, 0x20)
            if success {
                switch returndatasize()
                case 0 {
                    success := gt(extcodesize(token), 0)
                }
                default {
                    success := and(gt(returndatasize(), 31), eq(mload(0), 1))
                }
            }
        }
        if (!success) revert SafeTransferFromFailed();
    }

    /**
     * @notice Attempts to safely transfer tokens from one address to another using the Permit2 standard.
     * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
     * @param token The IERC20 token contract from which the tokens will be transferred.
     * @param from The address from which the tokens will be transferred.
     * @param to The address to which the tokens will be transferred.
     * @param amount The amount of tokens to transfer.
     */
    function safeTransferFromPermit2(
        IERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        if (amount > type(uint160).max) revert Permit2TransferAmountTooHigh();
        bytes4 selector = IPermit2.transferFrom.selector;
        bool success;
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            let data := mload(0x40)

            mstore(data, selector)
            mstore(add(data, 0x04), from)
            mstore(add(data, 0x24), to)
            mstore(add(data, 0x44), amount)
            mstore(add(data, 0x64), token)
            success := call(gas(), _PERMIT2, 0, data, 0x84, 0x0, 0x0)
            if success {
                success := gt(extcodesize(_PERMIT2), 0)
            }
        }
        if (!success) revert SafeTransferFromFailed();
    }

    /**
     * @notice Attempts to safely transfer tokens to another address.
     * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
     * @param token The IERC20 token contract from which the tokens will be transferred.
     * @param to The address to which the tokens will be transferred.
     * @param value The amount of tokens to transfer.
     */
    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        if (!_makeCall(token, token.transfer.selector, to, value)) {
            revert SafeTransferFailed();
        }
    }

    /**
     * @notice Attempts to approve a spender to spend a certain amount of tokens.
     * @dev If `approve(from, to, amount)` fails, it tries to set the allowance to zero, and retries the `approve` call.
     * @param token The IERC20 token contract on which the call will be made.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     */
    function forceApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        if (!_makeCall(token, token.approve.selector, spender, value)) {
            if (
                !_makeCall(token, token.approve.selector, spender, 0) ||
                !_makeCall(token, token.approve.selector, spender, value)
            ) {
                revert ForceApproveFailed();
            }
        }
    }

    /**
     * @notice Safely increases the allowance of a spender.
     * @dev Increases with safe math check. Checks if the increased allowance will overflow, if yes, then it reverts the transaction.
     * Then uses `forceApprove` to increase the allowance.
     * @param token The IERC20 token contract on which the call will be made.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to increase the allowance by.
     */
    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 allowance = token.allowance(address(this), spender);
        if (value > type(uint256).max - allowance) revert SafeIncreaseAllowanceFailed();
        forceApprove(token, spender, allowance + value);
    }

    /**
     * @notice Safely decreases the allowance of a spender.
     * @dev Decreases with safe math check. Checks if the decreased allowance will underflow, if yes, then it reverts the transaction.
     * Then uses `forceApprove` to increase the allowance.
     * @param token The IERC20 token contract on which the call will be made.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to decrease the allowance by.
     */
    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 allowance = token.allowance(address(this), spender);
        if (value > allowance) revert SafeDecreaseAllowanceFailed();
        forceApprove(token, spender, allowance - value);
    }

    /**
     * @notice Attempts to execute the `permit` function on the provided token with the sender and contract as parameters.
     * Permit type is determined automatically based on permit calldata (IERC20Permit, IDaiLikePermit, and IPermit2).
     * @dev Wraps `tryPermit` function and forwards revert reason if permit fails.
     * @param token The IERC20 token to execute the permit function on.
     * @param permit The permit data to be used in the function call.
     */
    function safePermit(IERC20 token, bytes calldata permit) internal {
        if (!tryPermit(token, msg.sender, address(this), permit)) RevertReasonForwarder.reRevert();
    }

    /**
     * @notice Attempts to execute the `permit` function on the provided token with custom owner and spender parameters. 
     * Permit type is determined automatically based on permit calldata (IERC20Permit, IDaiLikePermit, and IPermit2).
     * @dev Wraps `tryPermit` function and forwards revert reason if permit fails.
     * @param token The IERC20 token to execute the permit function on.
     * @param owner The owner of the tokens for which the permit is made.
     * @param spender The spender allowed to spend the tokens by the permit.
     * @param permit The permit data to be used in the function call.
     */
    function safePermit(IERC20 token, address owner, address spender, bytes calldata permit) internal {
        if (!tryPermit(token, owner, spender, permit)) RevertReasonForwarder.reRevert();
    }

    /**
     * @notice Attempts to execute the `permit` function on the provided token with the sender and contract as parameters.
     * @dev Invokes `tryPermit` with sender as owner and contract as spender.
     * @param token The IERC20 token to execute the permit function on.
     * @param permit The permit data to be used in the function call.
     * @return success Returns true if the permit function was successfully executed, false otherwise.
     */
    function tryPermit(IERC20 token, bytes calldata permit) internal returns(bool success) {
        return tryPermit(token, msg.sender, address(this), permit);
    }

    /**
     * @notice The function attempts to call the permit function on a given ERC20 token.
     * @dev The function is designed to support a variety of permit functions, namely: IERC20Permit, IDaiLikePermit, and IPermit2.
     * It accommodates both Compact and Full formats of these permit types.
     * Please note, it is expected that the `expiration` parameter for the compact Permit2 and the `deadline` parameter 
     * for the compact Permit are to be incremented by one before invoking this function. This approach is motivated by
     * gas efficiency considerations; as the unlimited expiration period is likely to be the most common scenario, and 
     * zeros are cheaper to pass in terms of gas cost. Thus, callers should increment the expiration or deadline by one
     * before invocation for optimized performance.
     * @param token The address of the ERC20 token on which to call the permit function.
     * @param owner The owner of the tokens. This address should have signed the off-chain permit.
     * @param spender The address which will be approved for transfer of tokens.
     * @param permit The off-chain permit data, containing different fields depending on the type of permit function.
     * @return success A boolean indicating whether the permit call was successful.
     */
    function tryPermit(IERC20 token, address owner, address spender, bytes calldata permit) internal returns(bool success) {
        // load function selectors for different permit standards
        bytes4 permitSelector = IERC20Permit.permit.selector;
        bytes4 daiPermitSelector = IDaiLikePermit.permit.selector;
        bytes4 permit2Selector = IPermit2.permit.selector;
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            let ptr := mload(0x40)

            // Switch case for different permit lengths, indicating different permit standards
            switch permit.length
            // Compact IERC20Permit
            case 100 {
                mstore(ptr, permitSelector)     // store selector
                mstore(add(ptr, 0x04), owner)   // store owner
                mstore(add(ptr, 0x24), spender) // store spender

                // Compact IERC20Permit.permit(uint256 value, uint32 deadline, uint256 r, uint256 vs)
                {  // stack too deep
                    let deadline := shr(224, calldataload(add(permit.offset, 0x20))) // loads permit.offset 0x20..0x23
                    let vs := calldataload(add(permit.offset, 0x44))                 // loads permit.offset 0x44..0x63

                    calldatacopy(add(ptr, 0x44), permit.offset, 0x20)            // store value     = copy permit.offset 0x00..0x19
                    mstore(add(ptr, 0x64), sub(deadline, 1))                     // store deadline  = deadline - 1
                    mstore(add(ptr, 0x84), add(27, shr(255, vs)))                // store v         = most significant bit of vs + 27 (27 or 28)
                    calldatacopy(add(ptr, 0xa4), add(permit.offset, 0x24), 0x20) // store r         = copy permit.offset 0x24..0x43
                    mstore(add(ptr, 0xc4), shr(1, shl(1, vs)))                   // store s         = vs without most significant bit
                }
                // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
                success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
            }
            // Compact IDaiLikePermit
            case 72 {
                mstore(ptr, daiPermitSelector)  // store selector
                mstore(add(ptr, 0x04), owner)   // store owner
                mstore(add(ptr, 0x24), spender) // store spender

                // Compact IDaiLikePermit.permit(uint32 nonce, uint32 expiry, uint256 r, uint256 vs)
                {  // stack too deep
                    let expiry := shr(224, calldataload(add(permit.offset, 0x04))) // loads permit.offset 0x04..0x07
                    let vs := calldataload(add(permit.offset, 0x28))               // loads permit.offset 0x28..0x47

                    mstore(add(ptr, 0x44), shr(224, calldataload(permit.offset))) // store nonce   = copy permit.offset 0x00..0x03
                    mstore(add(ptr, 0x64), sub(expiry, 1))                        // store expiry  = expiry - 1
                    mstore(add(ptr, 0x84), true)                                  // store allowed = true
                    mstore(add(ptr, 0xa4), add(27, shr(255, vs)))                 // store v       = most significant bit of vs + 27 (27 or 28)
                    calldatacopy(add(ptr, 0xc4), add(permit.offset, 0x08), 0x20)  // store r       = copy permit.offset 0x08..0x27
                    mstore(add(ptr, 0xe4), shr(1, shl(1, vs)))                    // store s       = vs without most significant bit
                }
                // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
                success := call(gas(), token, 0, ptr, 0x104, 0, 0)
            }
            // IERC20Permit
            case 224 {
                mstore(ptr, permitSelector)
                calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
                success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
            }
            // IDaiLikePermit
            case 256 {
                mstore(ptr, daiPermitSelector)
                calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
                success := call(gas(), token, 0, ptr, 0x104, 0, 0)
            }
            // Compact IPermit2
            case 96 {
                // Compact IPermit2.permit(uint160 amount, uint32 expiration, uint32 nonce, uint32 sigDeadline, uint256 r, uint256 vs)
                mstore(ptr, permit2Selector)  // store selector
                mstore(add(ptr, 0x04), owner) // store owner
                mstore(add(ptr, 0x24), token) // store token

                calldatacopy(add(ptr, 0x50), permit.offset, 0x14)             // store amount = copy permit.offset 0x00..0x13
                // and(0xffffffffffff, ...) - conversion to uint48 
                mstore(add(ptr, 0x64), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x14))), 1))) // store expiration = ((permit.offset 0x14..0x17 - 1) & 0xffffffffffff)
                mstore(add(ptr, 0x84), shr(224, calldataload(add(permit.offset, 0x18)))) // store nonce = copy permit.offset 0x18..0x1b
                mstore(add(ptr, 0xa4), spender)                               // store spender
                // and(0xffffffffffff, ...) - conversion to uint48
                mstore(add(ptr, 0xc4), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x1c))), 1))) // store sigDeadline = ((permit.offset 0x1c..0x1f - 1) & 0xffffffffffff)
                mstore(add(ptr, 0xe4), 0x100)                                 // store offset = 256
                mstore(add(ptr, 0x104), 0x40)                                 // store length = 64
                calldatacopy(add(ptr, 0x124), add(permit.offset, 0x20), 0x20) // store r      = copy permit.offset 0x20..0x3f
                calldatacopy(add(ptr, 0x144), add(permit.offset, 0x40), 0x20) // store vs     = copy permit.offset 0x40..0x5f
                // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
                success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0)
            }
            // IPermit2
            case 352 {
                mstore(ptr, permit2Selector)
                calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
                success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0)
            }
            // Unknown
            default {
                mstore(ptr, _PERMIT_LENGTH_ERROR)
                revert(ptr, 4)
            }
        }
    }

    /**
     * @dev Executes a low level call to a token contract, making it resistant to reversion and erroneous boolean returns.
     * @param token The IERC20 token contract on which the call will be made.
     * @param selector The function signature that is to be called on the token contract.
     * @param to The address to which the token amount will be transferred.
     * @param amount The token amount to be transferred.
     * @return success A boolean indicating if the call was successful. Returns 'true' on success and 'false' on failure. 
     * In case of success but no returned data, validates that the contract code exists.
     * In case of returned data, ensures that it's a boolean `true`.
     */
    function _makeCall(
        IERC20 token,
        bytes4 selector,
        address to,
        uint256 amount
    ) private returns (bool success) {
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            let data := mload(0x40)

            mstore(data, selector)
            mstore(add(data, 0x04), to)
            mstore(add(data, 0x24), amount)
            success := call(gas(), token, 0, data, 0x44, 0x0, 0x20)
            if success {
                switch returndatasize()
                case 0 {
                    success := gt(extcodesize(token), 0)
                }
                default {
                    success := and(gt(returndatasize(), 31), eq(mload(0), 1))
                }
            }
        }
    }

    /**
     * @notice Safely deposits a specified amount of Ether into the IWETH contract. Consumes less gas then regular `IWETH.deposit`.
     * @param weth The IWETH token contract.
     * @param amount The amount of Ether to deposit into the IWETH contract.
     */
    function safeDeposit(IWETH weth, uint256 amount) internal {
        if (amount > 0) {
            bytes4 selector = IWETH.deposit.selector;
            assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                mstore(0, selector)
                if iszero(call(gas(), weth, amount, 0, 4, 0, 0)) {
                    returndatacopy(0, 0, returndatasize())
                    revert(0, returndatasize())
                }
            }
        }
    }

    /**
     * @notice Safely withdraws a specified amount of wrapped Ether from the IWETH contract. Consumes less gas then regular `IWETH.withdraw`.
     * @dev Uses inline assembly to interact with the IWETH contract.
     * @param weth The IWETH token contract.
     * @param amount The amount of wrapped Ether to withdraw from the IWETH contract.
     */
    function safeWithdraw(IWETH weth, uint256 amount) internal {
        bytes4 selector = IWETH.withdraw.selector;
        assembly ("memory-safe") {  // solhint-disable-line no-inline-assembly
            mstore(0, selector)
            mstore(4, amount)
            if iszero(call(gas(), weth, 0, 0, 0x24, 0, 0)) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
        }
    }

    /**
     * @notice Safely withdraws a specified amount of wrapped Ether from the IWETH contract to a specified recipient.
     * Consumes less gas then regular `IWETH.withdraw`.
     * @param weth The IWETH token contract.
     * @param amount The amount of wrapped Ether to withdraw from the IWETH contract.
     * @param to The recipient of the withdrawn Ether.
     */
    function safeWithdrawTo(IWETH weth, uint256 amount, address to) internal {
        safeWithdraw(weth, amount);
        if (to != address(this)) {
            assembly ("memory-safe") {  // solhint-disable-line no-inline-assembly
                if iszero(call(_RAW_CALL_GAS_LIMIT, to, amount, 0, 0, 0, 0)) {
                    let ptr := mload(0x40)
                    returndatacopy(ptr, 0, returndatasize())
                    revert(ptr, returndatasize())
                }
            }
        }
    }
}

// File: verified-sources/0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6/sources/deployed-version-final/interfaces/ISwapManager.sol


pragma solidity ^0.8.18;

interface ISwapManager {
    function swap(bytes calldata data) external payable returns (uint256);
}
// File: verified-sources/0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6/sources/deployed-version-final/libraries/StringUtil.sol



pragma solidity ^0.8.0;

/// @title Library with gas-efficient string operations
library StringUtil {
    function toHex(uint256 value) internal pure returns (string memory) {
        return toHex(abi.encodePacked(value));
    }

    function toHex(address value) internal pure returns (string memory) {
        return toHex(abi.encodePacked(value));
    }

    /// @dev this is the assembly adaptation of highly optimized toHex16 code from Mikhail Vladimirov
    /// https://stackoverflow.com/a/69266989
    function toHex(bytes memory data) internal pure returns (string memory result) {
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            function _toHex16(input) -> output {
                output := or(
                    and(input, 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000),
                    shr(64, and(input, 0x0000000000000000FFFFFFFFFFFFFFFF00000000000000000000000000000000))
                )
                output := or(
                    and(output, 0xFFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000),
                    shr(32, and(output, 0x00000000FFFFFFFF000000000000000000000000FFFFFFFF0000000000000000))
                )
                output := or(
                    and(output, 0xFFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000),
                    shr(16, and(output, 0x0000FFFF000000000000FFFF000000000000FFFF000000000000FFFF00000000))
                )
                output := or(
                    and(output, 0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000),
                    shr(8, and(output, 0x00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000))
                )
                output := or(
                    shr(4, and(output, 0xF000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000)),
                    shr(8, and(output, 0x0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F00))
                )
                output := add(
                    add(0x3030303030303030303030303030303030303030303030303030303030303030, output),
                    mul(
                        and(
                            shr(4, add(output, 0x0606060606060606060606060606060606060606060606060606060606060606)),
                            0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F
                        ),
                        7 // Change 7 to 39 for lower case output
                    )
                )
            }

            result := mload(0x40)
            let length := mload(data)
            let resultLength := shl(1, length)
            let toPtr := add(result, 0x22) // 32 bytes for length + 2 bytes for '0x'
            mstore(0x40, add(toPtr, resultLength)) // move free memory pointer
            mstore(add(result, 2), 0x3078) // 0x3078 is right aligned so we write to `result + 2`
            // to store the last 2 bytes in the beginning of the string
            mstore(result, add(resultLength, 2)) // extra 2 bytes for '0x'

            for {
                let fromPtr := add(data, 0x20)
                let endPtr := add(fromPtr, length)
            } lt(fromPtr, endPtr) {
                fromPtr := add(fromPtr, 0x20)
            } {
                let rawData := mload(fromPtr)
                let hexData := _toHex16(rawData)
                mstore(toPtr, hexData)
                toPtr := add(toPtr, 0x20)
                hexData := _toHex16(shl(128, rawData))
                mstore(toPtr, hexData)
                toPtr := add(toPtr, 0x20)
            }
        }
    }
}

// File: verified-sources/0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6/sources/deployed-version-final/libraries/RevertReasonParser.sol



pragma solidity ^0.8.0;


/** @title Library that allows to parse unsuccessful arbitrary calls revert reasons.
 * See https://solidity.readthedocs.io/en/latest/control-structures.html#revert for details.
 * Note that we assume revert reason being abi-encoded as Error(string) so it may fail to parse reason
 * if structured reverts appear in the future.
 *
 * All unsuccessful parsings get encoded as Unknown(data) string
 */
library RevertReasonParser {
    using StringUtil for uint256;
    using StringUtil for bytes;

    error InvalidRevertReason();

    bytes4 private constant _ERROR_SELECTOR = bytes4(keccak256("Error(string)"));
    bytes4 private constant _PANIC_SELECTOR = bytes4(keccak256("Panic(uint256)"));

    /// @dev Parses error `data` and returns actual with `prefix`.
    function parse(bytes memory data, string memory prefix) internal pure returns (string memory) {
        // https://solidity.readthedocs.io/en/latest/control-structures.html#revert
        // We assume that revert reason is abi-encoded as Error(string)
        bytes4 selector;
        if (data.length >= 4) {
            assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                selector := mload(add(data, 0x20))
            }
        }

        // 68 = 4-byte selector + 32 bytes offset + 32 bytes length
        if (selector == _ERROR_SELECTOR && data.length >= 68) {
            string memory reason;
            assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                // 68 = 32 bytes data length + 4-byte selector + 32 bytes offset
                reason := add(data, 68)
            }
            /*
                revert reason is padded up to 32 bytes with ABI encoder: Error(string)
                also sometimes there is extra 32 bytes of zeros padded in the end:
                https://github.com/ethereum/solidity/issues/10170
                because of that we can't check for equality and instead check
                that string length + extra 68 bytes is equal or greater than overall data length
            */
            if (data.length >= 68 + bytes(reason).length) {
                return string.concat(prefix, "Error(", reason, ")");
            }
        }
        // 36 = 4-byte selector + 32 bytes integer
        else if (selector == _PANIC_SELECTOR && data.length == 36) {
            uint256 code;
            assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                // 36 = 32 bytes data length + 4-byte selector
                code := mload(add(data, 36))
            }
            return string.concat(prefix, "Panic(", code.toHex(), ")");
        }
        return string.concat(prefix, "Unknown(", data.toHex(), ")");
    }
}

// File: verified-sources/0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6/sources/deployed-version-final/libraries/PitERC20.sol


pragma solidity ^0.8.18;




library PitERC20 {
    using SafeERC20 for IERC20;
    using SafeERC20 for IWETH;

    error InsufficientBalance();
    error ApproveCalledOnETH();
    error NotEnoughValue();
    error FromIsNotSender();
    error ToIsNotThis();
    error ETHTransferFailed();
    error ExecutorError();

    uint256 private constant _RAW_CALL_GAS_LIMIT = 5000;
    uint256 private constant _MAX_APPROVE = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
    IERC20 private constant _ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
    IERC20 private constant _ZERO_ADDRESS = IERC20(address(0));
    IWETH internal constant WETH = IWETH(0xA1077a294dDE1B09bB078844df40758a5D0f9a27);

    /// @dev Returns true if `token` is ETH.
    function isETH(IERC20 token) internal pure returns (bool) {
        return (token == _ZERO_ADDRESS || token == _ETH_ADDRESS);
    }

    /// @dev Returns `account` ERC20 `token` balance.
    function pBalanceOf(IERC20 token, address account) internal view returns (uint256) {
        if (isETH(token)) {
            return account.balance;
        } else {
            return token.balanceOf(account);
        }
    }

    /// @dev Reverts if `token` is ETH, otherwise performs ERC20 forceApprove.
    function pApprove(
        IERC20 token,
        address to,
        uint256 amount
    ) internal {
        if (isETH(token)) revert ApproveCalledOnETH();
        uint256 allowance = token.allowance(address(this), to);
        if (allowance < amount) {
            token.forceApprove(to, _MAX_APPROVE);
        }
    }

    /// @dev Returns `account` ERC20 `token` balance.
    function pAmountFixer(IERC20 token, uint256 amount) internal view returns (uint256 fixedAmount) {
        address account = address(this);
        if (amount <= 0) {
            if (isETH(token)) {
                fixedAmount = account.balance;
            } else {
                fixedAmount = token.balanceOf(account);
            }
        }
        else {
            fixedAmount = amount;
        }
    }

    /// @dev `token` transfer `to` `amount`.
    /// Note that this function does nothing in case of zero amount.
    function pTransfer(
        IERC20 token,
        address payable to,
        uint256 amount
    ) internal {
        if (amount > 0) {
            if (isETH(token)) {
                if (address(this).balance < amount) revert InsufficientBalance();
                // solhint-disable-next-line avoid-low-level-calls
                (bool success, ) = to.call{value: amount, gas: _RAW_CALL_GAS_LIMIT}("");
                if (!success) revert ETHTransferFailed();
            } else {
                token.safeTransfer(to, amount);
            }
        }
    }

    function pTransferFrom(
        IERC20 token,
        address payable from,
        address to,
        uint256 amount
    ) internal {
        if (amount > 0) {
            if (isETH(token)) {
                if (msg.value < amount) revert NotEnoughValue();
                if (from != msg.sender) revert FromIsNotSender();
                if (to != address(this)) revert ToIsNotThis();
                if (msg.value > amount) {
                    // Return remainder if exist
                    unchecked {
                        // solhint-disable-next-line avoid-low-level-calls
                        (bool success, ) = from.call{value: msg.value - amount, gas: _RAW_CALL_GAS_LIMIT}("");
                        if (!success) revert ETHTransferFailed();
                    }
                }
            } else {
                token.safeTransferFrom(from, to, amount);
            }
        }
    }

    /// @dev `token` transfer `from` `to` `amount`.
    /// Note that this function does nothing in case of zero amount.
    function execute(
        IERC20 token,
        address payable from,
        address to,
        uint256 amount,
        bytes memory _data
    ) internal {
        if (amount > 0) {
            bool srcETH = isETH(token);
            if (!srcETH) {
                token.safeTransferFrom(from, to, amount);
            }
            (bool success, bytes memory result) = excessivelySafeCall(
                to,
                srcETH ? amount : 0,
                abi.encodeWithSelector(
                    ISwapManager.swap.selector,
                    _data
                )
            );
            if (!success) {
                revert(RevertReasonParser.parse(result, "Error: "));
            }
        }
    }

    
    function excessivelySafeCall(
        address _target,
        uint256 _value,
        bytes memory _calldata
    ) internal returns (bool _success, bytes memory _returnData) {
        // set up for assembly call
        uint256 _toCopy;
        //bool _success;
        // dispatch message to recipient
        // by assembly calling "handle" function
        // we call via assembly to avoid memcopying a very large returndata
        // returned by a malicious contract
        assembly {
            _success := call(
            gas(), // gas
            _target, // recipient
            _value, // ether value
            add(_calldata, 0x20), // inloc
            mload(_calldata), // inlen
            0, // outloc
            0 // outlen
            )
        // limit our copy to 256 bytes
            _toCopy := returndatasize()
        // Store the length of the copied bytes
            mstore(_returnData, _toCopy)
        // copy the bytes from returndata[0:_toCopy]
            returndatacopy(add(_returnData, 0x20), 0, _toCopy)
        }
        return (_success, _returnData);
    }

    function pDeposit(uint256 amount) internal {
        WETH.safeDeposit(amount);
    }

    function pWithdraw(uint256 amount) internal {
        WETH.safeWithdraw(amount);

    }
}
// File: verified-sources/0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6/sources/deployed-version-final/EthReceiver.sol



pragma solidity ^0.8.0;

abstract contract EthReceiver {
    error EthDepositRejected();

    receive() external payable {
        //_receive();
    }
    
    function _receive() internal virtual {
        // solhint-disable-next-line avoid-tx-origin
        if (msg.sender == tx.origin) revert EthDepositRejected();
    }
}

// File: verified-sources/0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6/sources/deployed-version-final/errors/Errors.sol


pragma solidity ^0.8.18;

contract Errors {
    error ZeroData();
    error ZeroAddress();
    error ZeroSrcAmount();
    error ZeroDestAmount();
    error ReturnAmountIsNotEnough();
    error ReturnAmountIsNotEqual();
    error InvalidMsgValue();
    error HasBeenStopped();
}
// File: verified-sources/0x6BF228eb7F8ad948d37deD07E595EfddfaAF88A6/sources/deployed-version-final/PiteasRouter.sol


pragma solidity ^0.8.18;






contract PiteasRouter is Ownable, EthReceiver {
    using PitERC20 for IERC20;
    using SafeMath for uint256;

    bool private status = true;
    address private swapManager;

    struct Detail {
        IERC20 srcToken;
        IERC20 destToken;
        address payable destAccount;
        uint256 srcAmount;
        uint256 destMinAmount;
    }

    event ChangedStatus(bool indexed status);
    event ChangedSwapManager(address indexed manager);
    event SwapEvent(
        address swapManager,
        IERC20 srcToken,
        IERC20 destToken,
        address indexed sender,
        address destReceiver,
        uint256 srcAmount,
        uint256 destAmount
    );

    modifier checkStatus() {
        if (status == false) {
            revert Errors.HasBeenStopped();
        }
        _;
    }

    function swap(Detail memory detail, bytes calldata data) public payable checkStatus returns (uint256 returnAmount)  {
        if (detail.srcAmount == 0) revert Errors.ZeroSrcAmount();
        if (detail.destMinAmount == 0) revert Errors.ZeroDestAmount();
        if (data.length == 0) revert Errors.ZeroData();

        IERC20 srcToken = detail.srcToken;
        IERC20 destToken = detail.destToken;
       
        bool srcETH = srcToken.isETH();
        if (msg.value < (srcETH ? detail.srcAmount : 0)) revert Errors.InvalidMsgValue();

        uint256 beginBalance = destToken.pBalanceOf(address(this));
        srcToken.execute(payable(msg.sender), swapManager, detail.srcAmount, data);
        returnAmount = destToken.pBalanceOf(address(this)).sub(beginBalance,"Error");
        
        address payable destReceiver = (detail.destAccount == address(0)) ? payable(msg.sender) : detail.destAccount;
        
        if (returnAmount >= detail.destMinAmount) {
            destToken.pTransfer(destReceiver, returnAmount);
        }else{
            revert Errors.ReturnAmountIsNotEnough();
        }

        emit SwapEvent(address(swapManager), srcToken, destToken, msg.sender, destReceiver, detail.srcAmount, returnAmount);
    }
    
    function changeStatus(bool _status) external onlyOwner {
        status = _status;
        emit ChangedStatus(_status);
    }

    function changeSwapManager(address _manager) external onlyOwner {
        if (_manager == address(0)) {
            revert Errors.ZeroAddress();
        }
        swapManager = _manager;
        emit ChangedSwapManager(_manager);
    }

    function withdrawFunds(IERC20 token, uint256 amount) external onlyOwner {
        token.pTransfer(payable(msg.sender), amount);
    }
}
        

Contract ABI

[{"type":"error","name":"ETHTransferFailed","inputs":[]},{"type":"error","name":"EthDepositRejected","inputs":[]},{"type":"error","name":"HasBeenStopped","inputs":[]},{"type":"error","name":"InsufficientBalance","inputs":[]},{"type":"error","name":"InvalidMsgValue","inputs":[]},{"type":"error","name":"ReturnAmountIsNotEnough","inputs":[]},{"type":"error","name":"SafeTransferFailed","inputs":[]},{"type":"error","name":"SafeTransferFromFailed","inputs":[]},{"type":"error","name":"ZeroAddress","inputs":[]},{"type":"error","name":"ZeroData","inputs":[]},{"type":"error","name":"ZeroDestAmount","inputs":[]},{"type":"error","name":"ZeroSrcAmount","inputs":[]},{"type":"event","name":"ChangedStatus","inputs":[{"type":"bool","name":"status","internalType":"bool","indexed":true}],"anonymous":false},{"type":"event","name":"ChangedSwapManager","inputs":[{"type":"address","name":"manager","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SwapEvent","inputs":[{"type":"address","name":"swapManager","internalType":"address","indexed":false},{"type":"address","name":"srcToken","internalType":"contract IERC20","indexed":false},{"type":"address","name":"destToken","internalType":"contract IERC20","indexed":false},{"type":"address","name":"sender","internalType":"address","indexed":true},{"type":"address","name":"destReceiver","internalType":"address","indexed":false},{"type":"uint256","name":"srcAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"destAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"changeStatus","inputs":[{"type":"bool","name":"_status","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"changeSwapManager","inputs":[{"type":"address","name":"_manager","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"returnAmount","internalType":"uint256"}],"name":"swap","inputs":[{"type":"tuple","name":"detail","internalType":"struct PiteasRouter.Detail","components":[{"type":"address","name":"srcToken","internalType":"contract IERC20"},{"type":"address","name":"destToken","internalType":"contract IERC20"},{"type":"address","name":"destAccount","internalType":"address payable"},{"type":"uint256","name":"srcAmount","internalType":"uint256"},{"type":"uint256","name":"destMinAmount","internalType":"uint256"}]},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawFunds","inputs":[{"type":"address","name":"token","internalType":"contract IERC20"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

Verify & Publish
0x60806040526001600060146101000a81548160ff02191690831515021790555034801561002b57600080fd5b5061004861003d61004d60201b60201c565b61005560201b60201c565b610119565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b611d1a806101286000396000f3fe6080604052600436106100745760003560e01c80638da5cb5b1161004e5780638da5cb5b146100f05780639b3de49b1461011b578063c107532914610144578063f2fde38b1461016d5761007b565b8063065a79ad14610080578063715018a6146100a95780638218b58f146100c05761007b565b3661007b57005b600080fd5b34801561008c57600080fd5b506100a760048036038101906100a29190611372565b610196565b005b3480156100b557600080fd5b506100be61028b565b005b6100da60048036038101906100d591906115d3565b61029f565b6040516100e79190611642565b60405180910390f35b3480156100fc57600080fd5b5061010561069e565b604051610112919061166c565b60405180910390f35b34801561012757600080fd5b50610142600480360381019061013d91906116bf565b6106c7565b005b34801561015057600080fd5b5061016b600480360381019061016691906116ec565b61071b565b005b34801561017957600080fd5b50610194600480360381019061018f9190611372565b610752565b005b61019e6107d5565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610204576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f9749619bcf6d1b4c60f22db410005b9501d48c42a749c4564585466fff64f34d60405160405180910390a250565b6102936107d5565b61029d6000610853565b565b6000801515600060149054906101000a900460ff161515036102ed576040517f4e43cc4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084606001510361032b576040517fe5ae137000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000846080015103610369576040517f175b9e6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083839050036103a6576040517fc922446b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008460000151905060008560200151905060006103d98373ffffffffffffffffffffffffffffffffffffffff16610917565b9050806103e75760006103ed565b86606001515b341015610426576040517f1841b4e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610451308473ffffffffffffffffffffffffffffffffffffffff1661099990919063ffffffff16565b90506104ec33600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a606001518a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508873ffffffffffffffffffffffffffffffffffffffff16610a4b90949392919063ffffffff16565b61055e816040518060400160405280600581526020017f4572726f7200000000000000000000000000000000000000000000000000000081525061054f308773ffffffffffffffffffffffffffffffffffffffff1661099990919063ffffffff16565b610bb39092919063ffffffff16565b945060008073ffffffffffffffffffffffffffffffffffffffff16896040015173ffffffffffffffffffffffffffffffffffffffff16146105a35788604001516105a5565b335b9050886080015186106105e2576105dd81878673ffffffffffffffffffffffffffffffffffffffff16610c089092919063ffffffff16565b610614565b6040517ff32bec2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff167faee0813f6f9fe55be44dd4c96b16d8b03085d3eb669fe21b51be0f4dc391622c600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168787858e606001518c60405161068a969594939291906117ac565b60405180910390a250505050509392505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6106cf6107d5565b80600060146101000a81548160ff0219169083151502179055508015157f030d1ae93bd878ad07bee72827dba91738e3b03307b607a679916911ea552b9960405160405180910390a250565b6107236107d5565b61074e33828473ffffffffffffffffffffffffffffffffffffffff16610c089092919063ffffffff16565b5050565b61075a6107d5565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036107c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c090611890565b60405180910390fd5b6107d281610853565b50565b6107dd610d39565b73ffffffffffffffffffffffffffffffffffffffff166107fb61069e565b73ffffffffffffffffffffffffffffffffffffffff1614610851576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610848906118fc565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480610992575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b9050919050565b60006109a483610917565b156109c8578173ffffffffffffffffffffffffffffffffffffffff16319050610a45565b8273ffffffffffffffffffffffffffffffffffffffff166370a08231836040518263ffffffff1660e01b8152600401610a01919061166c565b602060405180830381865afa158015610a1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a429190611931565b90505b92915050565b6000821115610bac576000610a5f86610917565b905080610a9457610a938585858973ffffffffffffffffffffffffffffffffffffffff16610d41909392919063ffffffff16565b5b600080610b248684610aa7576000610aa9565b865b63627dd56a60e01b87604051602401610ac291906119dd565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050610de0565b9150915081610ba857610b6c816040518060400160405280600781526020017f4572726f723a2000000000000000000000000000000000000000000000000000815250610e0c565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b9f9190611a43565b60405180910390fd5b5050505b5050505050565b6000838311158290610bfb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf29190611a43565b60405180910390fd5b5082840390509392505050565b6000811115610d3457610c1a83610917565b15610d075780471015610c59576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168261138890604051610c8390611a96565b600060405180830381858888f193505050503d8060008114610cc1576040519150601f19603f3d011682016040523d82523d6000602084013e610cc6565b606091505b5050905080610d01576040517fb12d13eb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610d33565b610d3282828573ffffffffffffffffffffffffffffffffffffffff16610fc79092919063ffffffff16565b5b5b505050565b600033905090565b60006323b872dd60e01b905060006040518281528560048201528460248201528360448201526020600060648360008b5af191508115610da0573d60008114610d9657600160005114601f3d11169250610d9e565b6000883b1192505b505b5080610dd8576040517ff405907100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b600060606000806000855160208701888a5af192503d9050808252806000602084013e50935093915050565b606060006004845110610e2157602084015190505b7f08c379a0afcc32b1a39302f7cb8073359698411ab5fd6e3edb2c02c0b5fba8aa7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148015610e9057506044845110155b15610ee357606060448501905080516044610eab9190611ada565b855110610edd578381604051602001610ec5929190611b96565b60405160208183030381529060405292505050610fc1565b50610f93565b7f4e487b71539e0164c9d29506cc725e49342bcac15e0927282bf30fedfe1c72687bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148015610f51575060248451145b15610f925760006024850151905083610f6982611015565b604051602001610f7a929190611bfe565b60405160208183030381529060405292505050610fc1565b5b82610f9d85611046565b604051602001610fae929190611c66565b6040516020818303038152906040529150505b92915050565b610fda8363a9059cbb60e01b84846112aa565b611010576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b606061103f8260405160200161102b9190611cc9565b604051602081830303815290604052611046565b9050919050565b6060611235565b600077ffffffffffffffff00000000000000000000000000000000821660401c7fffffffffffffffff00000000000000000000000000000000000000000000000083161790507bffffffff000000000000000000000000ffffffff0000000000000000811660201c7fffffffff000000000000000000000000ffffffff00000000000000000000000082161790507dffff000000000000ffff000000000000ffff000000000000ffff00000000811660101c7fffff000000000000ffff000000000000ffff000000000000ffff00000000000082161790507eff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0000811660081c7fff000000ff000000ff000000ff000000ff000000ff000000ff000000ff00000082161790507f0f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f00811660081c7ff000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000821660041c17905060077f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f0606060606060606060606060606060606060606060606060606060606060606830160041c1602817f303030303030303030303030303030303030303030303030303030303030303001019050919050565b604051905081518060011b602283018181016040526130786002850152600282018452602085018381015b808210156112a05781516112738161104d565b8085526020850194506112888260801b61104d565b90508085526020850194505050602082019150611260565b5050505050919050565b60006040518481528360048201528260248201526020600060448360008a5af1915081156112f7573d600081146112ed57600160005114601f3d111692506112f5565b6000873b1192505b505b50949350505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061133f82611314565b9050919050565b61134f81611334565b811461135a57600080fd5b50565b60008135905061136c81611346565b92915050565b6000602082840312156113885761138761130a565b5b60006113968482850161135d565b91505092915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6113ed826113a4565b810181811067ffffffffffffffff8211171561140c5761140b6113b5565b5b80604052505050565b600061141f611300565b905061142b82826113e4565b919050565b600061143b82611334565b9050919050565b61144b81611430565b811461145657600080fd5b50565b60008135905061146881611442565b92915050565b600061147982611314565b9050919050565b6114898161146e565b811461149457600080fd5b50565b6000813590506114a681611480565b92915050565b6000819050919050565b6114bf816114ac565b81146114ca57600080fd5b50565b6000813590506114dc816114b6565b92915050565b600060a082840312156114f8576114f761139f565b5b61150260a0611415565b9050600061151284828501611459565b600083015250602061152684828501611459565b602083015250604061153a84828501611497565b604083015250606061154e848285016114cd565b6060830152506080611562848285016114cd565b60808301525092915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126115935761159261156e565b5b8235905067ffffffffffffffff8111156115b0576115af611573565b5b6020830191508360018202830111156115cc576115cb611578565b5b9250929050565b600080600060c084860312156115ec576115eb61130a565b5b60006115fa868287016114e2565b93505060a084013567ffffffffffffffff81111561161b5761161a61130f565b5b6116278682870161157d565b92509250509250925092565b61163c816114ac565b82525050565b60006020820190506116576000830184611633565b92915050565b61166681611334565b82525050565b6000602082019050611681600083018461165d565b92915050565b60008115159050919050565b61169c81611687565b81146116a757600080fd5b50565b6000813590506116b981611693565b92915050565b6000602082840312156116d5576116d461130a565b5b60006116e3848285016116aa565b91505092915050565b600080604083850312156117035761170261130a565b5b600061171185828601611459565b9250506020611722858286016114cd565b9150509250929050565b6000819050919050565b600061175161174c61174784611314565b61172c565b611314565b9050919050565b600061176382611736565b9050919050565b600061177582611758565b9050919050565b6117858161176a565b82525050565b600061179682611758565b9050919050565b6117a68161178b565b82525050565b600060c0820190506117c1600083018961165d565b6117ce602083018861177c565b6117db604083018761177c565b6117e8606083018661179d565b6117f56080830185611633565b61180260a0830184611633565b979650505050505050565b600082825260208201905092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b600061187a60268361180d565b91506118858261181e565b604082019050919050565b600060208201905081810360008301526118a98161186d565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b60006118e660208361180d565b91506118f1826118b0565b602082019050919050565b60006020820190508181036000830152611915816118d9565b9050919050565b60008151905061192b816114b6565b92915050565b6000602082840312156119475761194661130a565b5b60006119558482850161191c565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561199857808201518184015260208101905061197d565b60008484015250505050565b60006119af8261195e565b6119b98185611969565b93506119c981856020860161197a565b6119d2816113a4565b840191505092915050565b600060208201905081810360008301526119f781846119a4565b905092915050565b600081519050919050565b6000611a15826119ff565b611a1f818561180d565b9350611a2f81856020860161197a565b611a38816113a4565b840191505092915050565b60006020820190508181036000830152611a5d8184611a0a565b905092915050565b600081905092915050565b50565b6000611a80600083611a65565b9150611a8b82611a70565b600082019050919050565b6000611aa182611a73565b9150819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611ae5826114ac565b9150611af0836114ac565b9250828201905080821115611b0857611b07611aab565b5b92915050565b600081905092915050565b6000611b24826119ff565b611b2e8185611b0e565b9350611b3e81856020860161197a565b80840191505092915050565b7f4572726f72280000000000000000000000000000000000000000000000000000815250565b7f2900000000000000000000000000000000000000000000000000000000000000815250565b6000611ba28285611b19565b9150611bad82611b4a565b600682019150611bbd8284611b19565b9150611bc882611b70565b6001820191508190509392505050565b7f50616e6963280000000000000000000000000000000000000000000000000000815250565b6000611c0a8285611b19565b9150611c1582611bd8565b600682019150611c258284611b19565b9150611c3082611b70565b6001820191508190509392505050565b7f556e6b6e6f776e28000000000000000000000000000000000000000000000000815250565b6000611c728285611b19565b9150611c7d82611c40565b600882019150611c8d8284611b19565b9150611c9882611b70565b6001820191508190509392505050565b6000819050919050565b611cc3611cbe826114ac565b611ca8565b82525050565b6000611cd58284611cb2565b6020820191508190509291505056fea264697066735822122028d1f65241f6c7f042eb2e5f9f950d2294ceb5fafb20f3229d7ec9561ad3de2164736f6c63430008120033

Deployed ByteCode

0x6080604052600436106100745760003560e01c80638da5cb5b1161004e5780638da5cb5b146100f05780639b3de49b1461011b578063c107532914610144578063f2fde38b1461016d5761007b565b8063065a79ad14610080578063715018a6146100a95780638218b58f146100c05761007b565b3661007b57005b600080fd5b34801561008c57600080fd5b506100a760048036038101906100a29190611372565b610196565b005b3480156100b557600080fd5b506100be61028b565b005b6100da60048036038101906100d591906115d3565b61029f565b6040516100e79190611642565b60405180910390f35b3480156100fc57600080fd5b5061010561069e565b604051610112919061166c565b60405180910390f35b34801561012757600080fd5b50610142600480360381019061013d91906116bf565b6106c7565b005b34801561015057600080fd5b5061016b600480360381019061016691906116ec565b61071b565b005b34801561017957600080fd5b50610194600480360381019061018f9190611372565b610752565b005b61019e6107d5565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610204576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f9749619bcf6d1b4c60f22db410005b9501d48c42a749c4564585466fff64f34d60405160405180910390a250565b6102936107d5565b61029d6000610853565b565b6000801515600060149054906101000a900460ff161515036102ed576040517f4e43cc4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084606001510361032b576040517fe5ae137000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000846080015103610369576040517f175b9e6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083839050036103a6576040517fc922446b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008460000151905060008560200151905060006103d98373ffffffffffffffffffffffffffffffffffffffff16610917565b9050806103e75760006103ed565b86606001515b341015610426576040517f1841b4e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610451308473ffffffffffffffffffffffffffffffffffffffff1661099990919063ffffffff16565b90506104ec33600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a606001518a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508873ffffffffffffffffffffffffffffffffffffffff16610a4b90949392919063ffffffff16565b61055e816040518060400160405280600581526020017f4572726f7200000000000000000000000000000000000000000000000000000081525061054f308773ffffffffffffffffffffffffffffffffffffffff1661099990919063ffffffff16565b610bb39092919063ffffffff16565b945060008073ffffffffffffffffffffffffffffffffffffffff16896040015173ffffffffffffffffffffffffffffffffffffffff16146105a35788604001516105a5565b335b9050886080015186106105e2576105dd81878673ffffffffffffffffffffffffffffffffffffffff16610c089092919063ffffffff16565b610614565b6040517ff32bec2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff167faee0813f6f9fe55be44dd4c96b16d8b03085d3eb669fe21b51be0f4dc391622c600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168787858e606001518c60405161068a969594939291906117ac565b60405180910390a250505050509392505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6106cf6107d5565b80600060146101000a81548160ff0219169083151502179055508015157f030d1ae93bd878ad07bee72827dba91738e3b03307b607a679916911ea552b9960405160405180910390a250565b6107236107d5565b61074e33828473ffffffffffffffffffffffffffffffffffffffff16610c089092919063ffffffff16565b5050565b61075a6107d5565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036107c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c090611890565b60405180910390fd5b6107d281610853565b50565b6107dd610d39565b73ffffffffffffffffffffffffffffffffffffffff166107fb61069e565b73ffffffffffffffffffffffffffffffffffffffff1614610851576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610848906118fc565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480610992575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b9050919050565b60006109a483610917565b156109c8578173ffffffffffffffffffffffffffffffffffffffff16319050610a45565b8273ffffffffffffffffffffffffffffffffffffffff166370a08231836040518263ffffffff1660e01b8152600401610a01919061166c565b602060405180830381865afa158015610a1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a429190611931565b90505b92915050565b6000821115610bac576000610a5f86610917565b905080610a9457610a938585858973ffffffffffffffffffffffffffffffffffffffff16610d41909392919063ffffffff16565b5b600080610b248684610aa7576000610aa9565b865b63627dd56a60e01b87604051602401610ac291906119dd565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050610de0565b9150915081610ba857610b6c816040518060400160405280600781526020017f4572726f723a2000000000000000000000000000000000000000000000000000815250610e0c565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b9f9190611a43565b60405180910390fd5b5050505b5050505050565b6000838311158290610bfb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf29190611a43565b60405180910390fd5b5082840390509392505050565b6000811115610d3457610c1a83610917565b15610d075780471015610c59576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168261138890604051610c8390611a96565b600060405180830381858888f193505050503d8060008114610cc1576040519150601f19603f3d011682016040523d82523d6000602084013e610cc6565b606091505b5050905080610d01576040517fb12d13eb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610d33565b610d3282828573ffffffffffffffffffffffffffffffffffffffff16610fc79092919063ffffffff16565b5b5b505050565b600033905090565b60006323b872dd60e01b905060006040518281528560048201528460248201528360448201526020600060648360008b5af191508115610da0573d60008114610d9657600160005114601f3d11169250610d9e565b6000883b1192505b505b5080610dd8576040517ff405907100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b600060606000806000855160208701888a5af192503d9050808252806000602084013e50935093915050565b606060006004845110610e2157602084015190505b7f08c379a0afcc32b1a39302f7cb8073359698411ab5fd6e3edb2c02c0b5fba8aa7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148015610e9057506044845110155b15610ee357606060448501905080516044610eab9190611ada565b855110610edd578381604051602001610ec5929190611b96565b60405160208183030381529060405292505050610fc1565b50610f93565b7f4e487b71539e0164c9d29506cc725e49342bcac15e0927282bf30fedfe1c72687bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148015610f51575060248451145b15610f925760006024850151905083610f6982611015565b604051602001610f7a929190611bfe565b60405160208183030381529060405292505050610fc1565b5b82610f9d85611046565b604051602001610fae929190611c66565b6040516020818303038152906040529150505b92915050565b610fda8363a9059cbb60e01b84846112aa565b611010576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b606061103f8260405160200161102b9190611cc9565b604051602081830303815290604052611046565b9050919050565b6060611235565b600077ffffffffffffffff00000000000000000000000000000000821660401c7fffffffffffffffff00000000000000000000000000000000000000000000000083161790507bffffffff000000000000000000000000ffffffff0000000000000000811660201c7fffffffff000000000000000000000000ffffffff00000000000000000000000082161790507dffff000000000000ffff000000000000ffff000000000000ffff00000000811660101c7fffff000000000000ffff000000000000ffff000000000000ffff00000000000082161790507eff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0000811660081c7fff000000ff000000ff000000ff000000ff000000ff000000ff000000ff00000082161790507f0f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f00811660081c7ff000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000821660041c17905060077f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f0606060606060606060606060606060606060606060606060606060606060606830160041c1602817f303030303030303030303030303030303030303030303030303030303030303001019050919050565b604051905081518060011b602283018181016040526130786002850152600282018452602085018381015b808210156112a05781516112738161104d565b8085526020850194506112888260801b61104d565b90508085526020850194505050602082019150611260565b5050505050919050565b60006040518481528360048201528260248201526020600060448360008a5af1915081156112f7573d600081146112ed57600160005114601f3d111692506112f5565b6000873b1192505b505b50949350505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061133f82611314565b9050919050565b61134f81611334565b811461135a57600080fd5b50565b60008135905061136c81611346565b92915050565b6000602082840312156113885761138761130a565b5b60006113968482850161135d565b91505092915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6113ed826113a4565b810181811067ffffffffffffffff8211171561140c5761140b6113b5565b5b80604052505050565b600061141f611300565b905061142b82826113e4565b919050565b600061143b82611334565b9050919050565b61144b81611430565b811461145657600080fd5b50565b60008135905061146881611442565b92915050565b600061147982611314565b9050919050565b6114898161146e565b811461149457600080fd5b50565b6000813590506114a681611480565b92915050565b6000819050919050565b6114bf816114ac565b81146114ca57600080fd5b50565b6000813590506114dc816114b6565b92915050565b600060a082840312156114f8576114f761139f565b5b61150260a0611415565b9050600061151284828501611459565b600083015250602061152684828501611459565b602083015250604061153a84828501611497565b604083015250606061154e848285016114cd565b6060830152506080611562848285016114cd565b60808301525092915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126115935761159261156e565b5b8235905067ffffffffffffffff8111156115b0576115af611573565b5b6020830191508360018202830111156115cc576115cb611578565b5b9250929050565b600080600060c084860312156115ec576115eb61130a565b5b60006115fa868287016114e2565b93505060a084013567ffffffffffffffff81111561161b5761161a61130f565b5b6116278682870161157d565b92509250509250925092565b61163c816114ac565b82525050565b60006020820190506116576000830184611633565b92915050565b61166681611334565b82525050565b6000602082019050611681600083018461165d565b92915050565b60008115159050919050565b61169c81611687565b81146116a757600080fd5b50565b6000813590506116b981611693565b92915050565b6000602082840312156116d5576116d461130a565b5b60006116e3848285016116aa565b91505092915050565b600080604083850312156117035761170261130a565b5b600061171185828601611459565b9250506020611722858286016114cd565b9150509250929050565b6000819050919050565b600061175161174c61174784611314565b61172c565b611314565b9050919050565b600061176382611736565b9050919050565b600061177582611758565b9050919050565b6117858161176a565b82525050565b600061179682611758565b9050919050565b6117a68161178b565b82525050565b600060c0820190506117c1600083018961165d565b6117ce602083018861177c565b6117db604083018761177c565b6117e8606083018661179d565b6117f56080830185611633565b61180260a0830184611633565b979650505050505050565b600082825260208201905092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b600061187a60268361180d565b91506118858261181e565b604082019050919050565b600060208201905081810360008301526118a98161186d565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b60006118e660208361180d565b91506118f1826118b0565b602082019050919050565b60006020820190508181036000830152611915816118d9565b9050919050565b60008151905061192b816114b6565b92915050565b6000602082840312156119475761194661130a565b5b60006119558482850161191c565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561199857808201518184015260208101905061197d565b60008484015250505050565b60006119af8261195e565b6119b98185611969565b93506119c981856020860161197a565b6119d2816113a4565b840191505092915050565b600060208201905081810360008301526119f781846119a4565b905092915050565b600081519050919050565b6000611a15826119ff565b611a1f818561180d565b9350611a2f81856020860161197a565b611a38816113a4565b840191505092915050565b60006020820190508181036000830152611a5d8184611a0a565b905092915050565b600081905092915050565b50565b6000611a80600083611a65565b9150611a8b82611a70565b600082019050919050565b6000611aa182611a73565b9150819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611ae5826114ac565b9150611af0836114ac565b9250828201905080821115611b0857611b07611aab565b5b92915050565b600081905092915050565b6000611b24826119ff565b611b2e8185611b0e565b9350611b3e81856020860161197a565b80840191505092915050565b7f4572726f72280000000000000000000000000000000000000000000000000000815250565b7f2900000000000000000000000000000000000000000000000000000000000000815250565b6000611ba28285611b19565b9150611bad82611b4a565b600682019150611bbd8284611b19565b9150611bc882611b70565b6001820191508190509392505050565b7f50616e6963280000000000000000000000000000000000000000000000000000815250565b6000611c0a8285611b19565b9150611c1582611bd8565b600682019150611c258284611b19565b9150611c3082611b70565b6001820191508190509392505050565b7f556e6b6e6f776e28000000000000000000000000000000000000000000000000815250565b6000611c728285611b19565b9150611c7d82611c40565b600882019150611c8d8284611b19565b9150611c9882611b70565b6001820191508190509392505050565b6000819050919050565b611cc3611cbe826114ac565b611ca8565b82525050565b6000611cd58284611cb2565b6020820191508190509291505056fea264697066735822122028d1f65241f6c7f042eb2e5f9f950d2294ceb5fafb20f3229d7ec9561ad3de2164736f6c63430008120033