Uninitialized lastWithdrawalTime allows immediate first withdrawal bypassing 30-day timelock
lastWithdrawalTime defaults to 0, so the first call to withdrawForStaking compares block.timestamp >= 30 days, which is always true.
Description
The withdrawForStaking function enforces a 30-day minimum interval between withdrawals to protect user funds from rapid extraction. However, the lastWithdrawalTime state variable is never initialized and defaults to 0, allowing the first withdrawal to bypass the timelock completely.
function withdrawForStaking(uint256 amount) external onlyOwner {require(msg.sender == founder || msg.sender == owner(), "Only founder");require(stakingActive, "Staking not active");require(amount > 0, "Amount must be > 0");require(block.timestamp >= lastWithdrawalTime + MIN_WITHDRAWAL_INTERVAL,"Must wait 30 days");uint256 availableBalance = stablecoin.balanceOf(address(this));require(availableBalance >= amount, "Insufficient balance");lastWithdrawalTime = block.timestamp;totalWithdrawnForStaking += amount;require(stablecoin.transfer(founder, amount), "Transfer failed");emit FundsWithdrawnForStaking(founder, amount);}
The timelock check at line 104-105 compares block.timestamp against lastWithdrawalTime + MIN_WITHDRAWAL_INTERVAL. When lastWithdrawalTime = 0, this becomes block.timestamp >= 0 + 30 days, which is always true since current Unix timestamps are far greater than 30 days (current time is ~1.7 billion seconds since epoch).
The 30-day withdrawal timelock is bypassed for the first withdrawal, allowing immediate extraction of all accumulated treasury funds. This defeats the purpose of the timelock protection, which is meant to prevent rapid fund extraction and provide transparency/security for users who contribute to the treasury through lottery participation. While the timelock functions correctly after the first withdrawal, the initial bypass creates a window where user funds are not adequately protected.
Recommendation
Adopt OpenZeppelin's SafeERC20 library for all ERC20 token interactions:
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";contract TreasuryBTC is Ownable, ReentrancyGuard {using SafeERC20 for IERC20;IERC20 public immutable stablecoin;IERC20 public immutable nxlToken;// Replace all transfers:// OLD: require(stablecoin.transfer(msg.sender, amount), "Transfer failed");// NEW: stablecoin.safeTransfer(msg.sender, amount);// OLD: require(stablecoin.transferFrom(msg.sender, address(this), amount), "Transfer failed");// NEW: stablecoin.safeTransferFrom(msg.sender, address(this), amount);// OLD: IERC20(token).transfer(owner(), amount);// NEW: IERC20(token).safeTransfer(owner(), amount);}
Resolution
Nexalo: Removed withdrawForStaking function.
Zealynx: With this design choice, the protocol no longer supports direct withdrawal of treasury funds for staking purposes.

