TruthTimedSellerV3

Description:

Decentralized Finance (DeFi) protocol contract providing Factory functionality.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

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

/// ---- Minimal ERC20 ----
interface IERC20 {
    function approve(address spender, uint256 value) external returns (bool);
    function transfer(address to, uint256 value) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
}

/// ---- Uniswap V3 Router (ExactInputSingle) ----
interface ISwapRouter {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24  fee;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96; // set 0 for no limit
    }

    function exactInputSingle(ExactInputSingleParams calldata params)
        external
        payable
        returns (uint256 amountOut);
}

/**
 * @title TruthTimedSellerV3
 * @notice Sells a fixed amount of TRUU for a chosen stable (USDC/USDT) via Uniswap V3.
 *         - No arrays (avoids the address issue entirely)
 *         - Cooldown enforces 1 run per interval (e.g., every 3 hours)
 *         - Owner/keeper can trigger `execute(minOut)`
 *         - Constructor grants router infinite TRUU approval (one-time)
 *         - Supports pause, sweep, and on-chain reconfiguration if ever needed (no code edits)
 */
contract TruthTimedSellerV3 {
    // ---- roles ----
    address public owner;
    address public keeper;
    bool    public paused;

    // ---- tokens & router ----
    IERC20 public immutable TRUU;
    IERC20 public immutable STABLE;
    ISwapRouter public constant ROUTER = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); // Uniswap V3 router

    // ---- config ----
    uint256 public sellAmount;   // TRUU amount in smallest units (TRUU has 10 decimals)
    uint24  public poolFee;      // e.g., 3000 for 0.3%, 10000 for 1.0%, 500 for 0.05%
    uint256 public interval;     // seconds between runs (e.g., 3 hours = 10800)

    // ---- state ----
    uint256 public lastExec;

    // ---- simple nonReentrant guard ----
    uint256 private _locked;
    modifier nonReentrant() {
        require(_locked == 0, "reentrancy");
        _locked = 1;
        _;
        _locked = 0;
    }

    modifier onlyOwner() { require(msg.sender == owner, "not owner"); _; }
    modifier onlyKeeperOrOwner() { require(msg.sender == keeper || msg.sender == owner, "not keeper/owner"); _; }
    modifier notPaused() { require(!paused, "paused"); _; }

    // ---- events ----
    event Executed(uint256 truuIn, uint256 stableOut, uint256 when);
    event KeeperSet(address keeper);
    event IntervalSet(uint256 secondsInterval);
    event SellAmountSet(uint256 amount);
    event PoolFeeSet(uint24 fee);
    event Paused(bool isPaused);

    /**
     * @param _truu      TRUU token address (ERC20)
     * @param _stable    Target stable (USDC or USDT) address (ERC20)
     * @param _keeper    Address allowed to call execute in addition to owner
     * @param _sellAmt   Fixed TRUU amount per run (include TRUU's 10 decimals)
     * @param _poolFee   Uniswap V3 pool fee (e.g., 3000 = 0.3%)
     * @param _interval  Cooldown in seconds (e.g., 10800 for 3 hours)
     */
    constructor(
        address _truu,
        address _stable,
        address _keeper,
        uint256 _sellAmt,
        uint24  _poolFee,
        uint256 _interval
    ) {
        owner     = msg.sender;
        keeper    = _keeper;
        TRUU      = IERC20(_truu);
        STABLE    = IERC20(_stable);
        sellAmount= _sellAmt;
        poolFee   = _poolFee;
        interval  = _interval;

        // One-time infinite approval so router can pull TRUU from this contract
        require(TRUU.approve(address(ROUTER), type(uint256).max), "approve fail");
    }

    // ---- admin (no code edits needed later; all on-chain) ----
    function setKeeper(address k) external onlyOwner { keeper = k; emit KeeperSet(k); }
    function setPaused(bool p) external onlyOwner { paused = p; emit Paused(p); }
    function setSellAmount(uint256 amt) external onlyOwner { sellAmount = amt; emit SellAmountSet(amt); }
    function setInterval(uint256 s) external onlyOwner { require(s >= 600, "min 10m"); interval = s; emit IntervalSet(s); }
    function setPoolFee(uint24 f) external onlyOwner { poolFee = f; emit PoolFeeSet(f); }

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

    /// @notice Execute one sell. Pass a conservative minOut (in STABLE units) or 0 to accept router quote.
    function execute(uint256 minOut) external onlyKeeperOrOwner notPaused nonReentrant {
        require(block.timestamp >= lastExec + interval, "cooldown");
        require(sellAmount > 0, "sellAmount=0");
        require(TRUU.balanceOf(address(this)) >= sellAmount, "insufficient TRUU");

        uint256 beforeBal = STABLE.balanceOf(address(this));

        ISwapRouter.ExactInputSingleParams memory p = ISwapRouter.ExactInputSingleParams({
            tokenIn: address(TRUU),
            tokenOut: address(STABLE),
            fee: poolFee,
            recipient: address(this), // receive here; transfer to owner below
            deadline: block.timestamp + 300, // 5 min to cut MEV/stale risk
            amountIn: sellAmount,
            amountOutMinimum: minOut,  // set >0 if you want protection, else 0
            sqrtPriceLimitX96: 0       // no price limit
        });

        uint256 outAmt = ROUTER.exactInputSingle(p);

        // Safety: if minOut==0 we still assert we got >0
        require(outAmt > 0, "no output");

        uint256 gained = STABLE.balanceOf(address(this)) - beforeBal;
        // send proceeds to owner
        if (gained > 0) {
            STABLE.transfer(owner, gained);
        }

        lastExec = block.timestamp;
        emit Executed(sellAmount, gained, lastExec);
    }

    // allow receiving ETH (not expected for stable routes, but harmless)
    receive() external payable {}
}"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": []
  }
}}

Tags:
DeFi, Factory|addr:0xeb7b2eafd892653f402b17ea35a58f421a13b51d|verified:true|block:23742762|tx:0x69257ec2b23e3c16346c8b5264bd8162366a26a7c9312c85a8d44e992380b7d9|first_check:1762508308

Submitted on: 2025-11-07 10:38:29

Comments

Log in to comment.

No comments yet.