SmartSplitSwapETH

Description:

Decentralized Finance (DeFi) protocol contract providing Swap, Factory functionality.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "SmartSplitSwapEth.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * ETH mainnet only:
 * - Send ETH to this contract → swaps ETH→USDT (Uniswap V2) → immediately splits to 3 recipients.
 * - depositUsdtAndSplit(amount): user approves USDT then splits.
 * - depositUsdtAndSplitWithPermit(...): one tx if token supports EIP-2612 (USDT usually doesn't; optional).
 * - depositTokenSwapAndSplit(token, amount): approve any ERC-20 → swap to USDT → split.
 *
 * NOTE: amountOutMin=0 for simplicity. Add slippage controls for production.
 */

interface IERC20 {
    function balanceOf(address) external view returns (uint256);
    function transfer(address to, uint256 v) external returns (bool);
    function approve(address s, uint256 v) external returns (bool);
    function transferFrom(address f, address t, uint256 v) external returns (bool);
}

interface IERC20Permit {
    function permit(
        address owner, address spender, uint value, uint deadline,
        uint8 v, bytes32 r, bytes32 s
    ) external;
}

library SafeERC20 {
    function safeTransfer(IERC20 t, address to, uint256 v) internal {
        require(t.transfer(to, v), "TRANSFER_FAIL");
    }
    function safeApprove(IERC20 t, address s, uint256 v) internal {
        // reset then set (safer for USDT-like tokens)
        require(t.approve(s, 0), "APPROVE_RESET_FAIL");
        require(t.approve(s, v), "APPROVE_FAIL");
    }
    function safeTransferFrom(IERC20 t, address f, address to, uint256 v) internal {
        require(t.transferFrom(f, to, v), "TRANSFER_FROM_FAIL");
    }
}

interface IUniswapV2Router02 {
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin, address[] calldata path, address to, uint deadline
    ) external payable;

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline
    ) external;
}

contract SmartSplitSwapETH {
    using SafeERC20 for IERC20;

    // ---- Ethereum mainnet constants ----
    address public constant ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D; // Uniswap V2
    address public constant WETH   = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address public constant USDT   = 0xdAC17F958D2ee523a2206206994597C13D831ec7;

    // ---- Split config ----
    address public owner;
    address[3] private recipients;
    uint16[3]  private shares; // e.g., [50,30,20] = 50/30/20
    uint16 public constant DENOMINATOR = 100;

    // ---- Events ----
    event Distributed(uint256 usdtAmount, address[3] recipients, uint16[3] shares);
    event RecipientsUpdated(address[3] recipients, uint16[3] shares);
    event OwnerUpdated(address newOwner);

    // ---- Auth ----
    modifier onlyOwner() { require(msg.sender == owner, "NOT_OWNER"); _; }

    // ---- Init ----
    constructor(address _owner, address[3] memory _recips, uint16[3] memory _shares) {
        require(_owner != address(0), "BAD_OWNER");
        uint sum = uint(_shares[0]) + _shares[1] + _shares[2];
        require(sum == DENOMINATOR, "SHARES_NOT_100%");
        for (uint i = 0; i < 3; i++) require(_recips[i] != address(0), "BAD_RECIP");
        owner = _owner;
        recipients = _recips;
        shares = _shares;
    }

    // ---------- Auto: receive ETH → swap to USDT → split ----------
    receive() external payable {
        require(msg.value > 0, "NO_ETH");

        // path: WETH -> USDT (router wraps ETH to WETH under the hood)
        address[] memory path = new address[](2);
        path[0] = WETH;
        path[1] = USDT;

        IUniswapV2Router02(ROUTER).swapExactETHForTokensSupportingFeeOnTransferTokens{value: msg.value}(
            0, // amountOutMin (slippage) = 0 for simplicity
            path,
            address(this),
            block.timestamp + 900
        );

        _splitUSDT(IERC20(USDT).balanceOf(address(this)));
    }

    // ---------- USDT deposit ----------
    /// Approve USDT first, then call this
    function depositUsdtAndSplit(uint256 amount) external {
        require(amount > 0, "AMOUNT_ZERO");
        IERC20(USDT).safeTransferFrom(msg.sender, address(this), amount);
        _splitUSDT(IERC20(USDT).balanceOf(address(this)));
    }

    /// If USDT supports EIP-2612 permit (most mainnet USDT does NOT; optional)
    function depositUsdtAndSplitWithPermit(
        uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s
    ) external {
        require(amount > 0, "AMOUNT_ZERO");
        IERC20Permit(USDT).permit(msg.sender, address(this), amount, deadline, v, r, s);
        IERC20(USDT).safeTransferFrom(msg.sender, address(this), amount);
        _splitUSDT(IERC20(USDT).balanceOf(address(this)));
    }

    // ---------- Any ERC-20: approve → pull → swap to USDT → split ----------
    function depositTokenSwapAndSplit(address token, uint256 amount) external {
        require(token != address(0), "BAD_TOKEN");
        require(amount > 0, "AMOUNT_ZERO");

        // Pull tokens
        IERC20(token).safeTransferFrom(msg.sender, address(this), amount);

        if (token == USDT) {
            _splitUSDT(IERC20(USDT).balanceOf(address(this)));
            return;
        }

        // Approve router for swap
        SafeERC20.safeApprove(IERC20(token), ROUTER, amount);

        // path: token -> WETH -> USDT
        address[] memory path = new address[](3);
        path[0] = token;
        path[1] = WETH;
        path[2] = USDT;

        IUniswapV2Router02(ROUTER).swapExactTokensForTokensSupportingFeeOnTransferTokens(
            amount,
            0, // amountOutMin = 0 (add slippage controls for production)
            path,
            address(this),
            block.timestamp + 900
        );

        _splitUSDT(IERC20(USDT).balanceOf(address(this)));
    }

    // ---------- Admin & utils ----------
    function getRecipients() external view returns (address[3] memory) {
        return recipients;
    }

    function getShares() external view returns (uint16[3] memory) {
        return shares;
    }

    function setRecipients(address[3] calldata _recips, uint16[3] calldata _shares) external onlyOwner {
        uint sum = uint(_shares[0]) + _shares[1] + _shares[2];
        require(sum == DENOMINATOR, "SHARES_NOT_100%");
        for (uint i = 0; i < 3; i++) require(_recips[i] != address(0), "BAD_RECIP");
        recipients = _recips;
        shares = _shares;
        emit RecipientsUpdated(recipients, shares);
    }

    function transferOwnership(address newOwner) external onlyOwner {
        require(newOwner != address(0), "BAD_OWNER");
        owner = newOwner;
        emit OwnerUpdated(newOwner);
    }

    /// If someone sent USDT by plain transfer, push it out
    function splitAllUSDT() external {
        _splitUSDT(IERC20(USDT).balanceOf(address(this)));
    }

    function rescueETH(address to) external onlyOwner {
        (bool ok,) = to.call{value: address(this).balance}("");
        require(ok, "ETH_FAIL");
    }

    function rescueToken(address token, address to, uint256 amount) external onlyOwner {
        IERC20(token).transfer(to, amount);
    }

    // ---------- Internal ----------
    function _splitUSDT(uint256 amount) internal {
        if (amount == 0) return;
        uint256 p0 = (amount * shares[0]) / DENOMINATOR;
        uint256 p1 = (amount * shares[1]) / DENOMINATOR;
        uint256 p2 = amount - p0 - p1; // avoid dust
        IERC20(USDT).safeTransfer(recipients[0], p0);
        IERC20(USDT).safeTransfer(recipients[1], p1);
        IERC20(USDT).safeTransfer(recipients[2], p2);
        emit Distributed(amount, recipients, shares);
    }
}
"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": false,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": []
  }
}}

Tags:
DeFi, Swap, Factory|addr:0xde69197d6bb462e797829aec1c010a6be08b4f21|verified:true|block:23479732|tx:0x28c446da116ec9a9c153aeb8bffc117a663f6ebb1b443d8116a8f2058a30fb3f|first_check:1759318528

Submitted on: 2025-10-01 13:35:28

Comments

Log in to comment.

No comments yet.