Treasury

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";

contract NEOPTreasury {
    address public timelock;
    IERC20 public immutable token;
    IUniswapV2Router02 public immutable router;

    event TokensSent(address indexed recipient, uint256 amount);
    event TokensBurned(uint256 amount);
    event LiquidityAdded(uint256 tokenAmount, uint256 ethAmount);

    modifier onlyTimelock() {
        require(msg.sender == timelock, "Not authorized");
        _;
    }

    constructor(address _timelock, address _token, address _router) {
        require(_timelock != address(0), "Zero timelock");
        require(_token != address(0), "Zero token");
        require(_router != address(0), "Zero router");

        timelock = _timelock;
        token = IERC20(_token);

        router = IUniswapV2Router02(_router);
    }

    function burn(uint256 amount) external onlyTimelock {
        ERC20Burnable(address(token)).burn(amount);

        emit TokensBurned(amount);
    }

    function addLiquidity(
        uint256 tokenAmount,
        uint256 slippageBps
    ) external payable onlyTimelock {
        uint256 half = tokenAmount / 2;
        uint256 otherHalf = tokenAmount - half;
        uint256 minToken = (otherHalf * (10000 - slippageBps)) / 10000;

        token.approve(address(router), tokenAmount);

        address[] memory path = new address[](2);
        path[0] = address(token);
        path[1] = router.WETH();

        uint256[] memory amounts = router.getAmountsOut(half, path);
        uint256 minEth = (amounts[1] * (10000 - slippageBps)) / 10000;

        router.swapExactTokensForETHSupportingFeeOnTransferTokens(
            half,
            minEth,
            path,
            address(this),
            block.timestamp
        );

        uint256 ethToLiq = address(this).balance;
        minEth = (ethToLiq * (10000 - slippageBps)) / 10000;

        router.addLiquidityETH{value: ethToLiq}(
            address(token),
            otherHalf,
            minToken,
            minEth,
            address(0xdead), // send LP tokens to dead address or treasury
            block.timestamp
        );

        emit LiquidityAdded(otherHalf, ethToLiq);
    }

    function sendTokens(
        address recipient,
        uint256 amount
    ) external onlyTimelock {
        require(recipient != address(0), "Zero address");
        token.transfer(recipient, amount);

        emit TokensSent(recipient, amount);
    }

    receive() external payable {}
}

Last updated