Accounts
0x4a...c04a
0x4A...C04a

0x4A...C04a

$500
This contract's source code is verified!
Contract Metadata
Compiler
0.8.24+commit.e11b9ed9
Language
Solidity
Contract Source Code
File 1 of 1: KaskadeRouterV1.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC20 {
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
}

library TransferHelper {
    function safeTransfer(address token, address to, uint256 value) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20(token).transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
    }

    function safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
    }
}

contract KaskadeRouterV1 {
    address private _owner;
    bool private _disabled;
    address public syncSwapContract; // Address of the SyncSwap contract

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event SwapSuccessful(address indexed user, uint amountOut, uint timestamp);
    event Disabled();

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor(address _syncSwapContract) {
        _transferOwnership(msg.sender);
        syncSwapContract = _syncSwapContract;
    }

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

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

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

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

    modifier ensure(uint deadline) {
        if (block.timestamp > deadline) {
            revert("Expired");
        }
        _;
    }

    modifier whenNotDisabled() {
        require(!_disabled, "Contract is disabled");
        _;
    }

    struct SwapPath {
        address tokenIn;
        uint amountIn;
        SwapStep[] steps;
    }

    struct SwapStep {
        address pool;
        bytes data;
        bool useVault;
        address callback;
        bytes callbackData;
    }

    struct TokenAmount {
        address token;
        uint amount;
    }

    function swapSyncSwap(
        SwapPath[] memory paths,
        uint amountOutMin,
        uint deadline
    ) external payable ensure(deadline) whenNotDisabled returns (TokenAmount memory amountOut) {
        // Delegate the call to the SyncSwap contract
        (bool success, bytes memory result) = syncSwapContract.delegatecall(
            abi.encodeWithSignature("swap((address,uint256,(address,bytes,bool,address,bytes)[])[],uint256,uint256)", paths, amountOutMin, deadline)
        );
        require(success, "Delegatecall to swap failed");
        amountOut = abi.decode(result, (TokenAmount));

        // Emit event for successful swap
        emit SwapSuccessful(msg.sender, amountOut.amount, block.timestamp);
    }

    function swap(
        bytes calldata callData
    ) external payable whenNotDisabled returns (TokenAmount memory amountOut) {
        // Delegate the call to the SyncSwap contract
        (bool success, bytes memory result) = syncSwapContract.delegatecall(
            callData
        );
        require(success, "Delegatecall to swap failed");
        amountOut = abi.decode(result, (TokenAmount));

        // Emit event for successful swap
        emit SwapSuccessful(msg.sender, amountOut.amount, block.timestamp);
    }

    function disable() external onlyOwner {
        _disabled = true;
        emit Disabled();
    }

    function isDisabled() external view returns (bool) {
        return _disabled;
    }



    function rescueERC20(address token, address to, uint256 amount) external onlyOwner {
        require(to != address(0) && to != token, "Invalid to");

        uint balance = IERC20(token).balanceOf(address(this));

        if (amount == 0) {
            TransferHelper.safeTransfer(token, to, balance);
        } else {
            require(amount <= balance, "Exceeds balance");
            TransferHelper.safeTransfer(token, to, amount);
        }
    }

    function rescueETH(address payable to, uint256 amount) external onlyOwner {
        if (amount == 0) {
            amount = address(this).balance;
        }
        TransferHelper.safeTransferETH(to, amount);
    }

    receive() external payable {}
}
Settings
{
  "compilationTarget": {
    "contracts/KaskadeRouterV1.sol": "KaskadeRouterV1"
  },
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"address","name":"_syncSwapContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[],"name":"Disabled","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":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"SwapSuccessful","type":"event"},{"inputs":[],"name":"disable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","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":"amount","type":"uint256"}],"name":"rescueERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"swap","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct KaskadeRouterV1.TokenAmount","name":"amountOut","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bool","name":"useVault","type":"bool"},{"internalType":"address","name":"callback","type":"address"},{"internalType":"bytes","name":"callbackData","type":"bytes"}],"internalType":"struct KaskadeRouterV1.SwapStep[]","name":"steps","type":"tuple[]"}],"internalType":"struct KaskadeRouterV1.SwapPath[]","name":"paths","type":"tuple[]"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapSyncSwap","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct KaskadeRouterV1.TokenAmount","name":"amountOut","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"syncSwapContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]