ETH Price: $2,522.96 (-0.58%)

Transaction Decoder

Block:
22714019 at Jun-16-2025 02:11:11 AM +UTC
Transaction Fee:
0.000185198813476796 ETH $0.47
Gas Used:
194,812 Gas / 0.950654033 Gwei

Emitted Events:

235 TetherToken.Transfer( from=[Sender] 0x33104af537b0f283b4ce650ef0130ffa990cfc20, to=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, value=200000000 )
236 WBTC.Transfer( from=0x56534741CD8B152df6d48AdF7ac51f75169A83b2, to=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, value=188770 )
237 TetherToken.Transfer( from=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, to=0x56534741CD8B152df6d48AdF7ac51f75169A83b2, value=200000000 )
238 0x56534741cd8b152df6d48adf7ac51f75169a83b2.0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67( 0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67, 0x0000000000000000000000003ced11c610556e5292fbc2e75d68c3899098c14c, 0x0000000000000000000000003ced11c610556e5292fbc2e75d68c3899098c14c, fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd1e9e, 000000000000000000000000000000000000000000000000000000000bebc200, 00000000000000000000000000000000000000208aaf57c071cc172982183263, 0000000000000000000000000000000000000000000000000000010582595273, 0000000000000000000000000000000000000000000000000000000000011015 )
239 0x3ced11c610556e5292fbc2e75d68c3899098c14c.0xbbb02a24579dc2e59c1609253b6ddab5457ba00895b3eda80dd41e03e2cd7e55( 0xbbb02a24579dc2e59c1609253b6ddab5457ba00895b3eda80dd41e03e2cd7e55, 0x000000000000000000000000ad27827c312cd5e71311d68e180a9872d42de23d, 0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7, 0x0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000003ced11c610556e5292fbc2e75d68c3899098c14c, 0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599, 000000000000000000000000000000000000000000000000000000000bebc200, 000000000000000000000000000000000000000000000000000000000002e162, ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0 )
240 WBTC.Transfer( from=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, to=TokenChwomper, value=93 )
241 WBTC.Transfer( from=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, to=TokenChwomper, value=376 )
242 WBTC.Transfer( from=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, to=[Sender] 0x33104af537b0f283b4ce650ef0130ffa990cfc20, value=188301 )

Account State Difference:

  Address   Before After State Difference Code
1.066016599620643227 Eth1.066114005620643227 Eth0.000097406
0x2260FAC5...93bc2C599
0x33104Af5...a990cFC20
0.086686005461890563 Eth
Nonce: 5
0.086500806648413767 Eth
Nonce: 6
0.000185198813476796
0x56534741...5169A83b2
(Uniswap V3: WBTC-USDT 2)
0xdAC17F95...13D831ec7

Execution Trace

RedSnwapper.snwap( tokenIn=0xdAC17F958D2ee523a2206206994597C13D831ec7, amountIn=200000000, recipient=0x33104Af537B0F283B4Ce650ef0130FFa990cFC20, tokenOut=0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, amountOutMin=187436, executor=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, executorData=0xBA3F2165000000000000000000000000DE7259893AF7CDBC9FD806C6BA61D22D581D566700000000000000000000000000000000000000000000000000000000000001D5000000000000000000000000DAC17F958D2EE523A2206206994597C13D831EC7000000000000000000000000000000000000000000000000000000000BEBC2000000000000000000000000002260FAC5E5542A773AA44FBCFEDF7C193BC2C599000000000000000000000000000000000000000000000000000000000002E1B200000000000000000000000033104AF537B0F283B4CE650EF0130FFA990CFC20000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004301DAC17F958D2EE523A2206206994597C13D831EC701FFFF0156534741CD8B152DF6D48ADF7AC51F75169A83B2003CED11C610556E5292FBC2E75D68C3899098C14C000000000000000000000000000000000000000000000000000000000000 ) => ( amountOut=188301 )
  • WBTC.balanceOf( _owner=0x33104Af537B0F283B4Ce650ef0130FFa990cFC20 ) => ( 0 )
  • TetherToken.transferFrom( _from=0x33104Af537B0F283B4Ce650ef0130FFa990cFC20, _to=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, _value=200000000 )
  • 0xad27827c312cd5e71311d68e180a9872d42de23d.1cff79cd( )
    • 0x3ced11c610556e5292fbc2e75d68c3899098c14c.ba3f2165( )
      • WBTC.balanceOf( _owner=0x3Ced11c610556e5292fBC2e75D68c3899098C14C ) => ( 1 )
      • TetherToken.balanceOf( who=0x3Ced11c610556e5292fBC2e75D68c3899098C14C ) => ( 200000001 )
      • Uniswap V3: WBTC-USDT 2.128acb08( )
        • WBTC.transfer( _to=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, _value=188770 ) => ( True )
        • TetherToken.balanceOf( who=0x56534741CD8B152df6d48AdF7ac51f75169A83b2 ) => ( 3582935728455 )
        • 0x3ced11c610556e5292fbc2e75d68c3899098c14c.fa461e33( )
          • TetherToken.transfer( _to=0x56534741CD8B152df6d48AdF7ac51f75169A83b2, _value=200000000 )
          • TetherToken.balanceOf( who=0x56534741CD8B152df6d48AdF7ac51f75169A83b2 ) => ( 3583135728455 )
          • WBTC.balanceOf( _owner=0x3Ced11c610556e5292fBC2e75D68c3899098C14C ) => ( 188771 )
          • WBTC.transfer( _to=0xde7259893Af7cdbC9fD806c6ba61D22D581d5667, _value=93 ) => ( True )
          • WBTC.transfer( _to=0xde7259893Af7cdbC9fD806c6ba61D22D581d5667, _value=376 ) => ( True )
          • WBTC.transfer( _to=0x33104Af537B0F283B4Ce650ef0130FFa990cFC20, _value=188301 ) => ( True )
          • WBTC.balanceOf( _owner=0x33104Af537B0F283B4Ce650ef0130FFa990cFC20 ) => ( 188301 )
            File 1 of 4: RedSnwapper
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-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);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.6.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);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
            pragma solidity ^0.8.0;
            import "../IERC20.sol";
            import "../extensions/draft-IERC20Permit.sol";
            import "../../../utils/Address.sol";
            /**
             * @title SafeERC20
             * @dev Wrappers around ERC20 operations that throw on failure (when the token
             * contract returns false). Tokens that return no value (and instead revert or
             * throw on failure) are also supported, non-reverting calls are assumed to be
             * successful.
             * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
             * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
             */
            library SafeERC20 {
                using Address for address;
                function safeTransfer(
                    IERC20 token,
                    address to,
                    uint256 value
                ) internal {
                    _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                }
                function safeTransferFrom(
                    IERC20 token,
                    address from,
                    address to,
                    uint256 value
                ) internal {
                    _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                }
                /**
                 * @dev Deprecated. This function has issues similar to the ones found in
                 * {IERC20-approve}, and its usage is discouraged.
                 *
                 * Whenever possible, use {safeIncreaseAllowance} and
                 * {safeDecreaseAllowance} instead.
                 */
                function safeApprove(
                    IERC20 token,
                    address spender,
                    uint256 value
                ) internal {
                    // safeApprove should only be called when setting an initial allowance,
                    // or when resetting it to zero. To increase and decrease it, use
                    // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                    require(
                        (value == 0) || (token.allowance(address(this), spender) == 0),
                        "SafeERC20: approve from non-zero to non-zero allowance"
                    );
                    _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
                }
                function safeIncreaseAllowance(
                    IERC20 token,
                    address spender,
                    uint256 value
                ) internal {
                    uint256 newAllowance = token.allowance(address(this), spender) + value;
                    _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                }
                function safeDecreaseAllowance(
                    IERC20 token,
                    address spender,
                    uint256 value
                ) internal {
                    unchecked {
                        uint256 oldAllowance = token.allowance(address(this), spender);
                        require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                        uint256 newAllowance = oldAllowance - value;
                        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                    }
                }
                function safePermit(
                    IERC20Permit token,
                    address owner,
                    address spender,
                    uint256 value,
                    uint256 deadline,
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                ) internal {
                    uint256 nonceBefore = token.nonces(owner);
                    token.permit(owner, spender, value, deadline, v, r, s);
                    uint256 nonceAfter = token.nonces(owner);
                    require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
                }
                /**
                 * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                 * on the return value: the return value is optional (but if data is returned, it must not be false).
                 * @param token The token targeted by the call.
                 * @param data The call data (encoded using abi.encode or one of its variants).
                 */
                function _callOptionalReturn(IERC20 token, bytes memory data) private {
                    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                    // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
                    // the target address contains contract code and also asserts for success in the low-level call.
                    bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                    if (returndata.length > 0) {
                        // Return data is optional
                        require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
            pragma solidity ^0.8.1;
            /**
             * @dev Collection of functions related to the address type
             */
            library Address {
                /**
                 * @dev Returns true if `account` is a contract.
                 *
                 * [IMPORTANT]
                 * ====
                 * It is unsafe to assume that an address for which this function returns
                 * false is an externally-owned account (EOA) and not a contract.
                 *
                 * Among others, `isContract` will return false for the following
                 * types of addresses:
                 *
                 *  - an externally-owned account
                 *  - a contract in construction
                 *  - an address where a contract will be created
                 *  - an address where a contract lived, but was destroyed
                 * ====
                 *
                 * [IMPORTANT]
                 * ====
                 * You shouldn't rely on `isContract` to protect against flash loan attacks!
                 *
                 * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                 * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                 * constructor.
                 * ====
                 */
                function isContract(address account) internal view returns (bool) {
                    // This method relies on extcodesize/address.code.length, which returns 0
                    // for contracts in construction, since the code is only stored at the end
                    // of the constructor execution.
                    return account.code.length > 0;
                }
                /**
                 * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                 * `recipient`, forwarding all available gas and reverting on errors.
                 *
                 * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                 * of certain opcodes, possibly making contracts go over the 2300 gas limit
                 * imposed by `transfer`, making them unable to receive funds via
                 * `transfer`. {sendValue} removes this limitation.
                 *
                 * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                 *
                 * IMPORTANT: because control is transferred to `recipient`, care must be
                 * taken to not create reentrancy vulnerabilities. Consider using
                 * {ReentrancyGuard} or the
                 * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                 */
                function sendValue(address payable recipient, uint256 amount) internal {
                    require(address(this).balance >= amount, "Address: insufficient balance");
                    (bool success, ) = recipient.call{value: amount}("");
                    require(success, "Address: unable to send value, recipient may have reverted");
                }
                /**
                 * @dev Performs a Solidity function call using a low level `call`. A
                 * plain `call` is an unsafe replacement for a function call: use this
                 * function instead.
                 *
                 * If `target` reverts with a revert reason, it is bubbled up by this
                 * function (like regular Solidity function calls).
                 *
                 * Returns the raw returned data. To convert to the expected return value,
                 * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                 *
                 * Requirements:
                 *
                 * - `target` must be a contract.
                 * - calling `target` with `data` must not revert.
                 *
                 * _Available since v3.1._
                 */
                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, 0, "Address: low-level call failed");
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                 * `errorMessage` as a fallback revert reason when `target` reverts.
                 *
                 * _Available since v3.1._
                 */
                function functionCall(
                    address target,
                    bytes memory data,
                    string memory errorMessage
                ) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, 0, errorMessage);
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but also transferring `value` wei to `target`.
                 *
                 * Requirements:
                 *
                 * - the calling contract must have an ETH balance of at least `value`.
                 * - the called Solidity function must be `payable`.
                 *
                 * _Available since v3.1._
                 */
                function functionCallWithValue(
                    address target,
                    bytes memory data,
                    uint256 value
                ) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                }
                /**
                 * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                 * with `errorMessage` as a fallback revert reason when `target` reverts.
                 *
                 * _Available since v3.1._
                 */
                function functionCallWithValue(
                    address target,
                    bytes memory data,
                    uint256 value,
                    string memory errorMessage
                ) internal returns (bytes memory) {
                    require(address(this).balance >= value, "Address: insufficient balance for call");
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a static call.
                 *
                 * _Available since v3.3._
                 */
                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                    return functionStaticCall(target, data, "Address: low-level static call failed");
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                 * but performing a static call.
                 *
                 * _Available since v3.3._
                 */
                function functionStaticCall(
                    address target,
                    bytes memory data,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a delegate call.
                 *
                 * _Available since v3.4._
                 */
                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                 * but performing a delegate call.
                 *
                 * _Available since v3.4._
                 */
                function functionDelegateCall(
                    address target,
                    bytes memory data,
                    string memory errorMessage
                ) internal returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                 *
                 * _Available since v4.8._
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    if (success) {
                        if (returndata.length == 0) {
                            // only check isContract if the call was successful and the return data is empty
                            // otherwise we already know that it was a contract
                            require(isContract(target), "Address: call to non-contract");
                        }
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason or using the provided one.
                 *
                 * _Available since v4.3._
                 */
                function verifyCallResult(
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal pure returns (bytes memory) {
                    if (success) {
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                function _revert(bytes memory returndata, string memory errorMessage) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
            // SPDX-License-Identifier: UNLICENSED
            pragma solidity 0.8.24;
            import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
            contract RedSnwapper {
              using SafeERC20 for IERC20;
              using Utils for IERC20;
              SafeExecutor public immutable safeExecutor;
              constructor() {
                safeExecutor = new SafeExecutor();
              }
              // @notice Swaps tokens
              // @notice 1. Transfers amountIn of tokens tokenIn to executor
              // @notice 2. launches executor with executorData and value = msg.value
              // @notice 3. Checks that recipient's tokenOut balance was increased at least amountOutMin
              function snwap(
                IERC20 tokenIn,
                uint amountIn, // if amountIn == 0 then amountIn = tokenIn.balance(this) - 1
                address recipient,
                IERC20 tokenOut,
                uint amountOutMin,
                address executor,
                bytes calldata executorData
              ) external payable returns (uint amountOut) {
                uint initialOutputBalance = tokenOut.universalBalanceOf(recipient);
                if (address(tokenIn) != NATIVE_ADDRESS) {
                  if (amountIn > 0) tokenIn.safeTransferFrom(msg.sender, executor, amountIn);
                  else tokenIn.safeTransfer(executor, tokenIn.balanceOf(address(this)) - 1); // -1 is slot undrain protection
                }
                safeExecutor.execute{value: msg.value}(executor, executorData);
                amountOut = tokenOut.universalBalanceOf(recipient) - initialOutputBalance;
                if (amountOut < amountOutMin)
                  revert MinimalOutputBalanceViolation(address(tokenOut), amountOut);
              }
              // @notice Swaps multiple tokens
              // @notice 1. Transfers inputTokens to inputTokens[i].transferTo
              // @notice 2. launches executors
              // @notice 3. Checks that recipient's tokenOut balance was increased at least amountOutMin
              function snwapMultiple(
                InputToken[] calldata inputTokens,
                OutputToken[] calldata outputTokens,
                Executor[] calldata executors
              ) external payable returns (uint[] memory amountOut) {
                uint[] memory initialOutputBalance = new uint[](outputTokens.length);
                for (uint i = 0; i < outputTokens.length; i++) {
                  initialOutputBalance[i] = outputTokens[i].token.universalBalanceOf(outputTokens[i].recipient);
                }
                for (uint i = 0; i < inputTokens.length; i++) {
                  IERC20 tokenIn = inputTokens[i].token;
                  if (address(tokenIn) != NATIVE_ADDRESS) {
                    if (inputTokens[i].amountIn > 0) 
                      tokenIn.safeTransferFrom(msg.sender, inputTokens[i].transferTo, inputTokens[i].amountIn);
                    else tokenIn.safeTransfer(inputTokens[i].transferTo, tokenIn.balanceOf(address(this)) - 1); // -1 is slot undrain protection
                  }
                }
                safeExecutor.executeMultiple{value: msg.value}(executors);
                amountOut = new uint[](outputTokens.length);
                for (uint i = 0; i < outputTokens.length; i++) {
                  amountOut[i] = outputTokens[i].token.universalBalanceOf(outputTokens[i].recipient) - initialOutputBalance[i];
                  if (amountOut[i] < outputTokens[i].amountOutMin)
                    revert MinimalOutputBalanceViolation(address(outputTokens[i].token), amountOut[i]);
                }
              }
            }
            // This contract doesn't have token approves, so can safely call other contracts
            contract SafeExecutor {  
              using Utils for address;
              function execute(address executor, bytes calldata executorData) external payable {
                executor.callRevertBubbleUp(msg.value, executorData);
              }
              function executeMultiple(Executor[] calldata executors) external payable {
                for (uint i = 0; i < executors.length; i++) {
                  executors[i].executor.callRevertBubbleUp(executors[i].value, executors[i].data);
                }
              }
            }
            error MinimalOutputBalanceViolation(address tokenOut, uint256 amountOut);
            address constant NATIVE_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
            struct InputToken {
              IERC20 token;
              uint amountIn;
              address transferTo;
            }
            struct OutputToken {
              IERC20 token;
              address recipient;
              uint amountOutMin;
            }
            struct Executor {
              address executor;
              uint value;
              bytes data;
            }
            library Utils {
              using SafeERC20 for IERC20;
              
              function universalBalanceOf(IERC20 token, address user) internal view returns (uint256) {
                if (address(token) == NATIVE_ADDRESS) return address(user).balance;
                else return token.balanceOf(user);
              }
              function callRevertBubbleUp(address contr, uint256 value, bytes memory data) internal {
                (bool success, bytes memory returnBytes) = contr.call{value: value}(data);
                if (!success) {
                  assembly {
                    revert(add(32, returnBytes), mload(returnBytes))
                  }
                }
              }
            }

            File 2 of 4: TetherToken
            pragma solidity ^0.4.17;
            
            /**
             * @title SafeMath
             * @dev Math operations with safety checks that throw on error
             */
            library SafeMath {
                function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                    if (a == 0) {
                        return 0;
                    }
                    uint256 c = a * b;
                    assert(c / a == b);
                    return c;
                }
            
                function div(uint256 a, uint256 b) internal pure returns (uint256) {
                    // assert(b > 0); // Solidity automatically throws when dividing by 0
                    uint256 c = a / b;
                    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                    return c;
                }
            
                function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                    assert(b <= a);
                    return a - b;
                }
            
                function add(uint256 a, uint256 b) internal pure returns (uint256) {
                    uint256 c = a + b;
                    assert(c >= a);
                    return c;
                }
            }
            
            /**
             * @title Ownable
             * @dev The Ownable contract has an owner address, and provides basic authorization control
             * functions, this simplifies the implementation of "user permissions".
             */
            contract Ownable {
                address public owner;
            
                /**
                  * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                  * account.
                  */
                function Ownable() public {
                    owner = msg.sender;
                }
            
                /**
                  * @dev Throws if called by any account other than the owner.
                  */
                modifier onlyOwner() {
                    require(msg.sender == owner);
                    _;
                }
            
                /**
                * @dev Allows the current owner to transfer control of the contract to a newOwner.
                * @param newOwner The address to transfer ownership to.
                */
                function transferOwnership(address newOwner) public onlyOwner {
                    if (newOwner != address(0)) {
                        owner = newOwner;
                    }
                }
            
            }
            
            /**
             * @title ERC20Basic
             * @dev Simpler version of ERC20 interface
             * @dev see https://github.com/ethereum/EIPs/issues/20
             */
            contract ERC20Basic {
                uint public _totalSupply;
                function totalSupply() public constant returns (uint);
                function balanceOf(address who) public constant returns (uint);
                function transfer(address to, uint value) public;
                event Transfer(address indexed from, address indexed to, uint value);
            }
            
            /**
             * @title ERC20 interface
             * @dev see https://github.com/ethereum/EIPs/issues/20
             */
            contract ERC20 is ERC20Basic {
                function allowance(address owner, address spender) public constant returns (uint);
                function transferFrom(address from, address to, uint value) public;
                function approve(address spender, uint value) public;
                event Approval(address indexed owner, address indexed spender, uint value);
            }
            
            /**
             * @title Basic token
             * @dev Basic version of StandardToken, with no allowances.
             */
            contract BasicToken is Ownable, ERC20Basic {
                using SafeMath for uint;
            
                mapping(address => uint) public balances;
            
                // additional variables for use if transaction fees ever became necessary
                uint public basisPointsRate = 0;
                uint public maximumFee = 0;
            
                /**
                * @dev Fix for the ERC20 short address attack.
                */
                modifier onlyPayloadSize(uint size) {
                    require(!(msg.data.length < size + 4));
                    _;
                }
            
                /**
                * @dev transfer token for a specified address
                * @param _to The address to transfer to.
                * @param _value The amount to be transferred.
                */
                function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
                    uint fee = (_value.mul(basisPointsRate)).div(10000);
                    if (fee > maximumFee) {
                        fee = maximumFee;
                    }
                    uint sendAmount = _value.sub(fee);
                    balances[msg.sender] = balances[msg.sender].sub(_value);
                    balances[_to] = balances[_to].add(sendAmount);
                    if (fee > 0) {
                        balances[owner] = balances[owner].add(fee);
                        Transfer(msg.sender, owner, fee);
                    }
                    Transfer(msg.sender, _to, sendAmount);
                }
            
                /**
                * @dev Gets the balance of the specified address.
                * @param _owner The address to query the the balance of.
                * @return An uint representing the amount owned by the passed address.
                */
                function balanceOf(address _owner) public constant returns (uint balance) {
                    return balances[_owner];
                }
            
            }
            
            /**
             * @title Standard ERC20 token
             *
             * @dev Implementation of the basic standard token.
             * @dev https://github.com/ethereum/EIPs/issues/20
             * @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
             */
            contract StandardToken is BasicToken, ERC20 {
            
                mapping (address => mapping (address => uint)) public allowed;
            
                uint public constant MAX_UINT = 2**256 - 1;
            
                /**
                * @dev Transfer tokens from one address to another
                * @param _from address The address which you want to send tokens from
                * @param _to address The address which you want to transfer to
                * @param _value uint the amount of tokens to be transferred
                */
                function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
                    var _allowance = allowed[_from][msg.sender];
            
                    // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
                    // if (_value > _allowance) throw;
            
                    uint fee = (_value.mul(basisPointsRate)).div(10000);
                    if (fee > maximumFee) {
                        fee = maximumFee;
                    }
                    if (_allowance < MAX_UINT) {
                        allowed[_from][msg.sender] = _allowance.sub(_value);
                    }
                    uint sendAmount = _value.sub(fee);
                    balances[_from] = balances[_from].sub(_value);
                    balances[_to] = balances[_to].add(sendAmount);
                    if (fee > 0) {
                        balances[owner] = balances[owner].add(fee);
                        Transfer(_from, owner, fee);
                    }
                    Transfer(_from, _to, sendAmount);
                }
            
                /**
                * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
                * @param _spender The address which will spend the funds.
                * @param _value The amount of tokens to be spent.
                */
                function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
            
                    // To change the approve amount you first have to reduce the addresses`
                    //  allowance to zero by calling `approve(_spender, 0)` if it is not
                    //  already 0 to mitigate the race condition described here:
                    //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                    require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
            
                    allowed[msg.sender][_spender] = _value;
                    Approval(msg.sender, _spender, _value);
                }
            
                /**
                * @dev Function to check the amount of tokens than an owner allowed to a spender.
                * @param _owner address The address which owns the funds.
                * @param _spender address The address which will spend the funds.
                * @return A uint specifying the amount of tokens still available for the spender.
                */
                function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                    return allowed[_owner][_spender];
                }
            
            }
            
            
            /**
             * @title Pausable
             * @dev Base contract which allows children to implement an emergency stop mechanism.
             */
            contract Pausable is Ownable {
              event Pause();
              event Unpause();
            
              bool public paused = false;
            
            
              /**
               * @dev Modifier to make a function callable only when the contract is not paused.
               */
              modifier whenNotPaused() {
                require(!paused);
                _;
              }
            
              /**
               * @dev Modifier to make a function callable only when the contract is paused.
               */
              modifier whenPaused() {
                require(paused);
                _;
              }
            
              /**
               * @dev called by the owner to pause, triggers stopped state
               */
              function pause() onlyOwner whenNotPaused public {
                paused = true;
                Pause();
              }
            
              /**
               * @dev called by the owner to unpause, returns to normal state
               */
              function unpause() onlyOwner whenPaused public {
                paused = false;
                Unpause();
              }
            }
            
            contract BlackList is Ownable, BasicToken {
            
                /////// Getters to allow the same blacklist to be used also by other contracts (including upgraded Tether) ///////
                function getBlackListStatus(address _maker) external constant returns (bool) {
                    return isBlackListed[_maker];
                }
            
                function getOwner() external constant returns (address) {
                    return owner;
                }
            
                mapping (address => bool) public isBlackListed;
                
                function addBlackList (address _evilUser) public onlyOwner {
                    isBlackListed[_evilUser] = true;
                    AddedBlackList(_evilUser);
                }
            
                function removeBlackList (address _clearedUser) public onlyOwner {
                    isBlackListed[_clearedUser] = false;
                    RemovedBlackList(_clearedUser);
                }
            
                function destroyBlackFunds (address _blackListedUser) public onlyOwner {
                    require(isBlackListed[_blackListedUser]);
                    uint dirtyFunds = balanceOf(_blackListedUser);
                    balances[_blackListedUser] = 0;
                    _totalSupply -= dirtyFunds;
                    DestroyedBlackFunds(_blackListedUser, dirtyFunds);
                }
            
                event DestroyedBlackFunds(address _blackListedUser, uint _balance);
            
                event AddedBlackList(address _user);
            
                event RemovedBlackList(address _user);
            
            }
            
            contract UpgradedStandardToken is StandardToken{
                // those methods are called by the legacy contract
                // and they must ensure msg.sender to be the contract address
                function transferByLegacy(address from, address to, uint value) public;
                function transferFromByLegacy(address sender, address from, address spender, uint value) public;
                function approveByLegacy(address from, address spender, uint value) public;
            }
            
            contract TetherToken is Pausable, StandardToken, BlackList {
            
                string public name;
                string public symbol;
                uint public decimals;
                address public upgradedAddress;
                bool public deprecated;
            
                //  The contract can be initialized with a number of tokens
                //  All the tokens are deposited to the owner address
                //
                // @param _balance Initial supply of the contract
                // @param _name Token Name
                // @param _symbol Token symbol
                // @param _decimals Token decimals
                function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public {
                    _totalSupply = _initialSupply;
                    name = _name;
                    symbol = _symbol;
                    decimals = _decimals;
                    balances[owner] = _initialSupply;
                    deprecated = false;
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function transfer(address _to, uint _value) public whenNotPaused {
                    require(!isBlackListed[msg.sender]);
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value);
                    } else {
                        return super.transfer(_to, _value);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
                    require(!isBlackListed[_from]);
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
                    } else {
                        return super.transferFrom(_from, _to, _value);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function balanceOf(address who) public constant returns (uint) {
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).balanceOf(who);
                    } else {
                        return super.balanceOf(who);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value);
                    } else {
                        return super.approve(_spender, _value);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                    if (deprecated) {
                        return StandardToken(upgradedAddress).allowance(_owner, _spender);
                    } else {
                        return super.allowance(_owner, _spender);
                    }
                }
            
                // deprecate current contract in favour of a new one
                function deprecate(address _upgradedAddress) public onlyOwner {
                    deprecated = true;
                    upgradedAddress = _upgradedAddress;
                    Deprecate(_upgradedAddress);
                }
            
                // deprecate current contract if favour of a new one
                function totalSupply() public constant returns (uint) {
                    if (deprecated) {
                        return StandardToken(upgradedAddress).totalSupply();
                    } else {
                        return _totalSupply;
                    }
                }
            
                // Issue a new amount of tokens
                // these tokens are deposited into the owner address
                //
                // @param _amount Number of tokens to be issued
                function issue(uint amount) public onlyOwner {
                    require(_totalSupply + amount > _totalSupply);
                    require(balances[owner] + amount > balances[owner]);
            
                    balances[owner] += amount;
                    _totalSupply += amount;
                    Issue(amount);
                }
            
                // Redeem tokens.
                // These tokens are withdrawn from the owner address
                // if the balance must be enough to cover the redeem
                // or the call will fail.
                // @param _amount Number of tokens to be issued
                function redeem(uint amount) public onlyOwner {
                    require(_totalSupply >= amount);
                    require(balances[owner] >= amount);
            
                    _totalSupply -= amount;
                    balances[owner] -= amount;
                    Redeem(amount);
                }
            
                function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner {
                    // Ensure transparency by hardcoding limit beyond which fees can never be added
                    require(newBasisPoints < 20);
                    require(newMaxFee < 50);
            
                    basisPointsRate = newBasisPoints;
                    maximumFee = newMaxFee.mul(10**decimals);
            
                    Params(basisPointsRate, maximumFee);
                }
            
                // Called when new token are issued
                event Issue(uint amount);
            
                // Called when tokens are redeemed
                event Redeem(uint amount);
            
                // Called when contract is deprecated
                event Deprecate(address newAddress);
            
                // Called if contract ever adds fees
                event Params(uint feeBasisPoints, uint maxFee);
            }

            File 3 of 4: WBTC
            pragma solidity 0.4.24;
            
            // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
            
            /**
             * @title ERC20Basic
             * @dev Simpler version of ERC20 interface
             * See https://github.com/ethereum/EIPs/issues/179
             */
            contract ERC20Basic {
              function totalSupply() public view returns (uint256);
              function balanceOf(address _who) public view returns (uint256);
              function transfer(address _to, uint256 _value) public returns (bool);
              event Transfer(address indexed from, address indexed to, uint256 value);
            }
            
            // File: openzeppelin-solidity/contracts/math/SafeMath.sol
            
            /**
             * @title SafeMath
             * @dev Math operations with safety checks that throw on error
             */
            library SafeMath {
            
              /**
              * @dev Multiplies two numbers, throws on overflow.
              */
              function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
                // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
                // benefit is lost if 'b' is also tested.
                // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                if (_a == 0) {
                  return 0;
                }
            
                c = _a * _b;
                assert(c / _a == _b);
                return c;
              }
            
              /**
              * @dev Integer division of two numbers, truncating the quotient.
              */
              function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
                // assert(_b > 0); // Solidity automatically throws when dividing by 0
                // uint256 c = _a / _b;
                // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
                return _a / _b;
              }
            
              /**
              * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
              */
              function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
                assert(_b <= _a);
                return _a - _b;
              }
            
              /**
              * @dev Adds two numbers, throws on overflow.
              */
              function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
                c = _a + _b;
                assert(c >= _a);
                return c;
              }
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC20/BasicToken.sol
            
            /**
             * @title Basic token
             * @dev Basic version of StandardToken, with no allowances.
             */
            contract BasicToken is ERC20Basic {
              using SafeMath for uint256;
            
              mapping(address => uint256) internal balances;
            
              uint256 internal totalSupply_;
            
              /**
              * @dev Total number of tokens in existence
              */
              function totalSupply() public view returns (uint256) {
                return totalSupply_;
              }
            
              /**
              * @dev Transfer token for a specified address
              * @param _to The address to transfer to.
              * @param _value The amount to be transferred.
              */
              function transfer(address _to, uint256 _value) public returns (bool) {
                require(_value <= balances[msg.sender]);
                require(_to != address(0));
            
                balances[msg.sender] = balances[msg.sender].sub(_value);
                balances[_to] = balances[_to].add(_value);
                emit Transfer(msg.sender, _to, _value);
                return true;
              }
            
              /**
              * @dev Gets the balance of the specified address.
              * @param _owner The address to query the the balance of.
              * @return An uint256 representing the amount owned by the passed address.
              */
              function balanceOf(address _owner) public view returns (uint256) {
                return balances[_owner];
              }
            
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
            
            /**
             * @title ERC20 interface
             * @dev see https://github.com/ethereum/EIPs/issues/20
             */
            contract ERC20 is ERC20Basic {
              function allowance(address _owner, address _spender)
                public view returns (uint256);
            
              function transferFrom(address _from, address _to, uint256 _value)
                public returns (bool);
            
              function approve(address _spender, uint256 _value) public returns (bool);
              event Approval(
                address indexed owner,
                address indexed spender,
                uint256 value
              );
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol
            
            /**
             * @title Standard ERC20 token
             *
             * @dev Implementation of the basic standard token.
             * https://github.com/ethereum/EIPs/issues/20
             * Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
             */
            contract StandardToken is ERC20, BasicToken {
            
              mapping (address => mapping (address => uint256)) internal allowed;
            
            
              /**
               * @dev Transfer tokens from one address to another
               * @param _from address The address which you want to send tokens from
               * @param _to address The address which you want to transfer to
               * @param _value uint256 the amount of tokens to be transferred
               */
              function transferFrom(
                address _from,
                address _to,
                uint256 _value
              )
                public
                returns (bool)
              {
                require(_value <= balances[_from]);
                require(_value <= allowed[_from][msg.sender]);
                require(_to != address(0));
            
                balances[_from] = balances[_from].sub(_value);
                balances[_to] = balances[_to].add(_value);
                allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
                emit Transfer(_from, _to, _value);
                return true;
              }
            
              /**
               * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
               * 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
               * @param _spender The address which will spend the funds.
               * @param _value The amount of tokens to be spent.
               */
              function approve(address _spender, uint256 _value) public returns (bool) {
                allowed[msg.sender][_spender] = _value;
                emit Approval(msg.sender, _spender, _value);
                return true;
              }
            
              /**
               * @dev Function to check the amount of tokens that an owner allowed to a spender.
               * @param _owner address The address which owns the funds.
               * @param _spender address The address which will spend the funds.
               * @return A uint256 specifying the amount of tokens still available for the spender.
               */
              function allowance(
                address _owner,
                address _spender
               )
                public
                view
                returns (uint256)
              {
                return allowed[_owner][_spender];
              }
            
              /**
               * @dev Increase the amount of tokens that an owner allowed to a spender.
               * approve should be called when allowed[_spender] == 0. To increment
               * allowed value is better to use this function to avoid 2 calls (and wait until
               * the first transaction is mined)
               * From MonolithDAO Token.sol
               * @param _spender The address which will spend the funds.
               * @param _addedValue The amount of tokens to increase the allowance by.
               */
              function increaseApproval(
                address _spender,
                uint256 _addedValue
              )
                public
                returns (bool)
              {
                allowed[msg.sender][_spender] = (
                  allowed[msg.sender][_spender].add(_addedValue));
                emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
                return true;
              }
            
              /**
               * @dev Decrease the amount of tokens that an owner allowed to a spender.
               * approve should be called when allowed[_spender] == 0. To decrement
               * allowed value is better to use this function to avoid 2 calls (and wait until
               * the first transaction is mined)
               * From MonolithDAO Token.sol
               * @param _spender The address which will spend the funds.
               * @param _subtractedValue The amount of tokens to decrease the allowance by.
               */
              function decreaseApproval(
                address _spender,
                uint256 _subtractedValue
              )
                public
                returns (bool)
              {
                uint256 oldValue = allowed[msg.sender][_spender];
                if (_subtractedValue >= oldValue) {
                  allowed[msg.sender][_spender] = 0;
                } else {
                  allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
                }
                emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
                return true;
              }
            
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol
            
            /**
             * @title DetailedERC20 token
             * @dev The decimals are only for visualization purposes.
             * All the operations are done using the smallest and indivisible token unit,
             * just as on Ethereum all the operations are done in wei.
             */
            contract DetailedERC20 is ERC20 {
              string public name;
              string public symbol;
              uint8 public decimals;
            
              constructor(string _name, string _symbol, uint8 _decimals) public {
                name = _name;
                symbol = _symbol;
                decimals = _decimals;
              }
            }
            
            // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
            
            /**
             * @title Ownable
             * @dev The Ownable contract has an owner address, and provides basic authorization control
             * functions, this simplifies the implementation of "user permissions".
             */
            contract Ownable {
              address public owner;
            
            
              event OwnershipRenounced(address indexed previousOwner);
              event OwnershipTransferred(
                address indexed previousOwner,
                address indexed newOwner
              );
            
            
              /**
               * @dev The Ownable constructor sets the original `owner` of the contract to the sender
               * account.
               */
              constructor() public {
                owner = msg.sender;
              }
            
              /**
               * @dev Throws if called by any account other than the owner.
               */
              modifier onlyOwner() {
                require(msg.sender == owner);
                _;
              }
            
              /**
               * @dev Allows the current owner to relinquish control of the contract.
               * @notice Renouncing to ownership will leave the contract without an owner.
               * It will not be possible to call the functions with the `onlyOwner`
               * modifier anymore.
               */
              function renounceOwnership() public onlyOwner {
                emit OwnershipRenounced(owner);
                owner = address(0);
              }
            
              /**
               * @dev Allows the current owner to transfer control of the contract to a newOwner.
               * @param _newOwner The address to transfer ownership to.
               */
              function transferOwnership(address _newOwner) public onlyOwner {
                _transferOwnership(_newOwner);
              }
            
              /**
               * @dev Transfers control of the contract to a newOwner.
               * @param _newOwner The address to transfer ownership to.
               */
              function _transferOwnership(address _newOwner) internal {
                require(_newOwner != address(0));
                emit OwnershipTransferred(owner, _newOwner);
                owner = _newOwner;
              }
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol
            
            /**
             * @title Mintable token
             * @dev Simple ERC20 Token example, with mintable token creation
             * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
             */
            contract MintableToken is StandardToken, Ownable {
              event Mint(address indexed to, uint256 amount);
              event MintFinished();
            
              bool public mintingFinished = false;
            
            
              modifier canMint() {
                require(!mintingFinished);
                _;
              }
            
              modifier hasMintPermission() {
                require(msg.sender == owner);
                _;
              }
            
              /**
               * @dev Function to mint tokens
               * @param _to The address that will receive the minted tokens.
               * @param _amount The amount of tokens to mint.
               * @return A boolean that indicates if the operation was successful.
               */
              function mint(
                address _to,
                uint256 _amount
              )
                public
                hasMintPermission
                canMint
                returns (bool)
              {
                totalSupply_ = totalSupply_.add(_amount);
                balances[_to] = balances[_to].add(_amount);
                emit Mint(_to, _amount);
                emit Transfer(address(0), _to, _amount);
                return true;
              }
            
              /**
               * @dev Function to stop minting new tokens.
               * @return True if the operation was successful.
               */
              function finishMinting() public onlyOwner canMint returns (bool) {
                mintingFinished = true;
                emit MintFinished();
                return true;
              }
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC20/BurnableToken.sol
            
            /**
             * @title Burnable Token
             * @dev Token that can be irreversibly burned (destroyed).
             */
            contract BurnableToken is BasicToken {
            
              event Burn(address indexed burner, uint256 value);
            
              /**
               * @dev Burns a specific amount of tokens.
               * @param _value The amount of token to be burned.
               */
              function burn(uint256 _value) public {
                _burn(msg.sender, _value);
              }
            
              function _burn(address _who, uint256 _value) internal {
                require(_value <= balances[_who]);
                // no need to require value <= totalSupply, since that would imply the
                // sender's balance is greater than the totalSupply, which *should* be an assertion failure
            
                balances[_who] = balances[_who].sub(_value);
                totalSupply_ = totalSupply_.sub(_value);
                emit Burn(_who, _value);
                emit Transfer(_who, address(0), _value);
              }
            }
            
            // File: openzeppelin-solidity/contracts/lifecycle/Pausable.sol
            
            /**
             * @title Pausable
             * @dev Base contract which allows children to implement an emergency stop mechanism.
             */
            contract Pausable is Ownable {
              event Pause();
              event Unpause();
            
              bool public paused = false;
            
            
              /**
               * @dev Modifier to make a function callable only when the contract is not paused.
               */
              modifier whenNotPaused() {
                require(!paused);
                _;
              }
            
              /**
               * @dev Modifier to make a function callable only when the contract is paused.
               */
              modifier whenPaused() {
                require(paused);
                _;
              }
            
              /**
               * @dev called by the owner to pause, triggers stopped state
               */
              function pause() public onlyOwner whenNotPaused {
                paused = true;
                emit Pause();
              }
            
              /**
               * @dev called by the owner to unpause, returns to normal state
               */
              function unpause() public onlyOwner whenPaused {
                paused = false;
                emit Unpause();
              }
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC20/PausableToken.sol
            
            /**
             * @title Pausable token
             * @dev StandardToken modified with pausable transfers.
             **/
            contract PausableToken is StandardToken, Pausable {
            
              function transfer(
                address _to,
                uint256 _value
              )
                public
                whenNotPaused
                returns (bool)
              {
                return super.transfer(_to, _value);
              }
            
              function transferFrom(
                address _from,
                address _to,
                uint256 _value
              )
                public
                whenNotPaused
                returns (bool)
              {
                return super.transferFrom(_from, _to, _value);
              }
            
              function approve(
                address _spender,
                uint256 _value
              )
                public
                whenNotPaused
                returns (bool)
              {
                return super.approve(_spender, _value);
              }
            
              function increaseApproval(
                address _spender,
                uint _addedValue
              )
                public
                whenNotPaused
                returns (bool success)
              {
                return super.increaseApproval(_spender, _addedValue);
              }
            
              function decreaseApproval(
                address _spender,
                uint _subtractedValue
              )
                public
                whenNotPaused
                returns (bool success)
              {
                return super.decreaseApproval(_spender, _subtractedValue);
              }
            }
            
            // File: openzeppelin-solidity/contracts/ownership/Claimable.sol
            
            /**
             * @title Claimable
             * @dev Extension for the Ownable contract, where the ownership needs to be claimed.
             * This allows the new owner to accept the transfer.
             */
            contract Claimable is Ownable {
              address public pendingOwner;
            
              /**
               * @dev Modifier throws if called by any account other than the pendingOwner.
               */
              modifier onlyPendingOwner() {
                require(msg.sender == pendingOwner);
                _;
              }
            
              /**
               * @dev Allows the current owner to set the pendingOwner address.
               * @param newOwner The address to transfer ownership to.
               */
              function transferOwnership(address newOwner) public onlyOwner {
                pendingOwner = newOwner;
              }
            
              /**
               * @dev Allows the pendingOwner address to finalize the transfer.
               */
              function claimOwnership() public onlyPendingOwner {
                emit OwnershipTransferred(owner, pendingOwner);
                owner = pendingOwner;
                pendingOwner = address(0);
              }
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol
            
            /**
             * @title SafeERC20
             * @dev Wrappers around ERC20 operations that throw on failure.
             * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
             * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
             */
            library SafeERC20 {
              function safeTransfer(
                ERC20Basic _token,
                address _to,
                uint256 _value
              )
                internal
              {
                require(_token.transfer(_to, _value));
              }
            
              function safeTransferFrom(
                ERC20 _token,
                address _from,
                address _to,
                uint256 _value
              )
                internal
              {
                require(_token.transferFrom(_from, _to, _value));
              }
            
              function safeApprove(
                ERC20 _token,
                address _spender,
                uint256 _value
              )
                internal
              {
                require(_token.approve(_spender, _value));
              }
            }
            
            // File: openzeppelin-solidity/contracts/ownership/CanReclaimToken.sol
            
            /**
             * @title Contracts that should be able to recover tokens
             * @author SylTi
             * @dev This allow a contract to recover any ERC20 token received in a contract by transferring the balance to the contract owner.
             * This will prevent any accidental loss of tokens.
             */
            contract CanReclaimToken is Ownable {
              using SafeERC20 for ERC20Basic;
            
              /**
               * @dev Reclaim all ERC20Basic compatible tokens
               * @param _token ERC20Basic The address of the token contract
               */
              function reclaimToken(ERC20Basic _token) external onlyOwner {
                uint256 balance = _token.balanceOf(this);
                _token.safeTransfer(owner, balance);
              }
            
            }
            
            // File: contracts/utils/OwnableContract.sol
            
            // empty block is used as this contract just inherits others.
            contract OwnableContract is CanReclaimToken, Claimable { } /* solhint-disable-line no-empty-blocks */
            
            // File: contracts/token/WBTC.sol
            
            contract WBTC is StandardToken, DetailedERC20("Wrapped BTC", "WBTC", 8),
                MintableToken, BurnableToken, PausableToken, OwnableContract {
            
                function burn(uint value) public onlyOwner {
                    super.burn(value);
                }
            
                function finishMinting() public onlyOwner returns (bool) {
                    return false;
                }
            
                function renounceOwnership() public onlyOwner {
                    revert("renouncing ownership is blocked");
                }
            }

            File 4 of 4: TokenChwomper
            // SPDX-License-Identifier: MIT
            // 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);
            }// SPDX-License-Identifier: UNLICENSED
            pragma solidity >= 0.8.0;
            interface IRedSnwapper {
                struct InputToken {
                    address token;
                    uint256 amountIn;
                    address transferTo;
                }
                struct OutputToken {
                    address token;
                    address recipient;
                    uint256 amountOutMin;
                }
                struct Executor {
                    address executor;
                    uint256 value;
                    bytes data;
                }
                function snwap(
                    address tokenIn,
                    uint256 amountIn,
                    address recipient,
                    address tokenOut,
                    uint256 amountOutMin,
                    address executor,
                    bytes calldata executorData
                ) external returns (uint256 amountOut);
                function snwapMultiple(
                    InputToken[] calldata inputTokens,
                    OutputToken[] calldata outputTokens,
                    Executor[] calldata executors
                ) external returns (uint256[] memory amountOut);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
            pragma solidity ^0.8.0;
            import "../utils/Context.sol";
            /**
             * @dev Contract module which provides a basic access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * 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 anymore. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby removing 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);
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)
            pragma solidity ^0.8.0;
            import "./Ownable.sol";
            /**
             * @dev Contract module which provides 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} and {acceptOwnership}.
             *
             * This module is used through inheritance. It will make available all functions
             * from parent (Ownable).
             */
            abstract contract Ownable2Step is Ownable {
                address private _pendingOwner;
                event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Returns the address of the pending owner.
                 */
                function pendingOwner() public view virtual returns (address) {
                    return _pendingOwner;
                }
                /**
                 * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual override onlyOwner {
                    _pendingOwner = newOwner;
                    emit OwnershipTransferStarted(owner(), newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual override {
                    delete _pendingOwner;
                    super._transferOwnership(newOwner);
                }
                /**
                 * @dev The new owner accepts the ownership transfer.
                 */
                function acceptOwnership() external {
                    address sender = _msgSender();
                    require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
                    _transferOwnership(sender);
                }
            }
            // SPDX-License-Identifier: MIT
            // 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;
                }
            }
            // SPDX-License-Identifier: GPL-3.0-or-later
            pragma solidity >=0.8.0;
            import "openzeppelin/access/Ownable2Step.sol";
            abstract contract Auth is Ownable2Step {
                event SetTrusted(address indexed user, bool isTrusted);
                mapping(address => bool) public trusted;
                error OnlyTrusted();
                modifier onlyTrusted() {
                    if (!trusted[msg.sender]) revert OnlyTrusted();
                    _;
                }
                constructor(address trustedUser) {
                    trusted[trustedUser] = true;
                    emit SetTrusted(trustedUser, true);
                }
                function setTrusted(address user, bool isTrusted) external onlyOwner {
                    trusted[user] = isTrusted;
                    emit SetTrusted(user, isTrusted);
                }
            }// SPDX-License-Identifier: GPL-3.0-or-later
            pragma solidity >=0.8.0;
            import "interfaces/IRedSnwapper.sol";
            import "interfaces/IERC20.sol";
            import "./Auth.sol";
            /// @title TokenChwomper for selling accumulated tokens for weth or other base assets
            /// @notice This contract will be used for fee collection and breakdown
            /// @dev Uses Auth contract for 2-step owner process and trust operators to guard functions
            contract TokenChwomper is Auth {
              address public immutable weth;
              IRedSnwapper public redSnwapper;
              bytes4 private constant TRANSFER_SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
              error TransferFailed();
              constructor(
                address _operator,
                address _redSnwapper,
                address _weth
              ) Auth(_operator) {
                // initial owner is msg.sender
                redSnwapper = IRedSnwapper(_redSnwapper);
                weth = _weth;
              }
              /// @notice Updates the RedSnwapper to be used for swapping tokens
              /// @dev make sure new RedSnwapper is backwards compatiable (should be)
              /// @param _redSnwapper The address of the new route processor
              function updateRedSnwapper(address _redSnwapper) external onlyOwner {
                redSnwapper = IRedSnwapper(_redSnwapper);
              }
              
              /// @notice Swaps tokens via the configured RedSnwapper
              /// @dev Must be called by a trusted operator
              /// @param tokenIn Address of the input token
              /// @param amountIn Amount of the input token to swap
              /// @param recipient Address to receive the output tokens
              /// @param tokenOut Address of the output token
              /// @param amountOutMin Minimum acceptable amount of output tokens (slippage protection)
              /// @param executor Address of the executor contract to perform the swap logic
              /// @param executorData Encoded data for the executor call
              /// @return amountOut The actual amount of output tokens received
              function snwap(
                address tokenIn,
                uint256 amountIn,
                address recipient,
                address tokenOut,
                uint256 amountOutMin,
                address executor,
                bytes calldata executorData
              ) external onlyTrusted returns (uint256 amountOut) {
                 // Pre-fund RedSnwapper with input tokens
                 _safeTransfer(tokenIn, address(redSnwapper), amountIn);
                // Execute snwap with zero amountIn
                amountOut = redSnwapper.snwap(
                  tokenIn,
                  0,
                  recipient,
                  tokenOut,
                  amountOutMin,
                  executor,
                  executorData
                );
              }
              /// @notice Performs multiple swaps via the configured RedSnwapper
              /// @dev Must be called by a trusted operator
              /// @param inputTokens Array of input token parameters
              /// @param outputTokens Array of output token requirements
              /// @param executors Array of executor calls to perform
              /// @return amountOut Array of actual amounts of output tokens received
              function snwapMultiple(
                IRedSnwapper.InputToken[] calldata inputTokens,
                IRedSnwapper.OutputToken[] calldata outputTokens,
                IRedSnwapper.Executor[] calldata executors
              ) external onlyTrusted returns (uint256[] memory amountOut) {
               uint256 length = inputTokens.length;
                IRedSnwapper.InputToken[] memory _inputTokens = new IRedSnwapper.InputToken[](length);
                for (uint256 i = 0; i < length; ++i) {
                    // Pre-fund RedSnwapper with input tokens
                    _safeTransfer(
                        inputTokens[i].token,
                        address(redSnwapper),
                        inputTokens[i].amountIn
                    );
                    // Build _inputTokens with zero amountIn
                    _inputTokens[i] = IRedSnwapper.InputToken({
                        token: inputTokens[i].token,
                        amountIn: 0,
                        transferTo: inputTokens[i].transferTo
                    });
                }
                // Execute snwapMultiple
                amountOut = redSnwapper.snwapMultiple(
                    _inputTokens,
                    outputTokens,
                    executors
                );
              }
              /// @notice Withdraw any token or eth from the contract
              /// @dev can only be called by owner
              /// @param token The address of the token to be withdrawn, 0x0 for eth
              /// @param to The address to send the token to
              /// @param _value The amount of the token to be withdrawn
              function withdraw(address token, address to, uint256 _value) onlyOwner external {
                if (token != address(0)) {
                  _safeTransfer(token, to, _value);
                } 
                else {
                  (bool success, ) = to.call{value: _value}("");
                  require(success);
                }
              }
              
              function _safeTransfer(address token, address to, uint value) internal {
                (bool success, bytes memory data) = token.call(abi.encodeWithSelector(TRANSFER_SELECTOR, to, value));
                if (!success || (data.length != 0 && !abi.decode(data, (bool)))) revert TransferFailed();
              }
              /// @notice In case we receive any unwrapped eth (native token) we can call this
              /// @dev operators can call this 
              function wrapEth() onlyTrusted external {
                weth.call{value: address(this).balance}("");
              }
              /// @notice Available function in case we need to do any calls that aren't supported by the contract (unwinding lp positions, etc.)
              /// @dev can only be called by owner
              /// @param to The address to send the call to
              /// @param _value The amount of eth to send with the call
              /// @param data The data to be sent with the call
              function doAction(address to, uint256 _value, bytes memory data) onlyOwner external {
                (bool success, ) = to.call{value: _value}(data);
                require(success);
              }
              receive() external payable {}
            }