TokenChwomper

0x7282249282902e1f99c2cb0a04230091bd30fe3a

Verification
Unverified
v0.8.20+commit.a1b79de6
Type
Contract
6,374 bytes
ABI entries
22
5 read · 10 write
License
none

Contract information

Address
0x7282249282902e1f99c2cb0a04230091bd30fe3a
Chain
Robinhood Chain (4663)
Compiler
v0.8.20+commit.a1b79de6
Optimization
Enabled
Creation tx
0x54ef680c50…b9539816d6

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (5)

owner()address
pendingOwner()address
redSnwapper()address
trusted(address)bool
weth()address

Events (3)

OwnershipTransferStartedOwnershipTransferredSetTrusted

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_operator",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "_redSnwapper",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "_weth",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "OnlyTrusted",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TransferFailed",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferStarted",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "isTrusted",
        "type": "bool"
      }
    ],
    "name": "SetTrusted",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "acceptOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "_value",
        "type": "uint256"
      },
      {
        "internalType": "bytes",
        "name": "data",
        "type": "bytes"
      }
    ],
    "name": "doAction",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pendingOwner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "redSnwapper",
    "outputs": [
      {
        "internalType": "contract IRedSnwapper",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "isTrusted",
        "type": "bool"
      }
    ],
    "name": "setTrusted",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "tokenIn",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amountIn",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "tokenOut",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amountOutMin",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "executor",
        "type": "address"
      },
      {
        "internalType": "bytes",
        "name": "executorData",
        "type": "bytes"
      }
    ],
    "name": "snwap",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "amountOut",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "token",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "amountIn",
            "type": "uint256"
          },
          {
            "internalType": "address",
            "name": "transferTo",
            "type": "address"
          }
        ],
        "internalType": "struct IRedSnwapper.InputToken[]",
        "name": "inputTokens",
        "type": "tuple[]"
      },
      {
        "components": [
          {
            "internalType": "address",
            "name": "token",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "recipient",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "amountOutMin",
            "type": "uint256"
          }
        ],
        "internalType": "struct IRedSnwapper.OutputToken[]",
        "name": "outputTokens",
        "type": "tuple[]"
      },
      {
        "components": [
          {
            "internalType": "address",
            "name": "executor",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "value",
            "type": "uint256"
          },
          {
            "internalType": "bytes",
            "name": "data",
            "type": "bytes"
          }
        ],
        "internalType": "struct IRedSnwapper.Executor[]",
        "name": "executors",
        "type": "tuple[]"
      }
    ],
    "name": "snwapMultiple",
    "outputs": [
      {
        "internalType": "uint256[]",
        "name": "amountOut",
        "type": "uint256[]"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "trusted",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_redSnwapper",
        "type": "address"
      }
    ],
    "name": "updateRedSnwapper",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "weth",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "_value",
        "type": "uint256"
      }
    ],
    "name": "withdraw",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "wrapEth",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

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

  address private constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
  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) {
    if (tokenIn == NATIVE_TOKEN) {
      amountOut = redSnwapper.snwap{ value: amountIn }(
        tokenIn,
        amountIn,
        recipient,
        tokenOut,
        amountOutMin,
        executor,
        executorData
      );
    } else {
      // 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);
    uint256 value = 0;
    for (uint256 i = 0; i < length; ++i) {
      if (inputTokens[i].token == NATIVE_TOKEN) {
        value += inputTokens[i].amountIn;
        _inputTokens[i] = inputTokens[i];
      } else {
        // 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{value: value}(
        _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 {}
}
Chain explorer2161msChain node73ms