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": []
}
}}
Submitted on: 2025-10-01 13:35:28
Comments
Log in to comment.
No comments yet.