Run 0xdeadbeef…c3e9 · Vault.sol · solc 0.8.24 · 2,098ms
Critical
1
High
3
Medium
1
Low
0
Info
2
7 findings
Critical RE-01 Reentrancy in withdraw() Vault.sol:184

The withdraw() function sends ETH to msg.sender before updating the balance mapping. A malicious contract can re-enter withdraw() in its receive() fallback, draining the vault before any balance is decremented. SWC-107.

182function withdraw(uint256 amount) external {
183 require(balances[msg.sender] >= amount);
184 (bool ok,) = msg.sender.call{value: amount}(""); // ← sends before state update
185 require(ok);
186 balances[msg.sender] -= amount; // ← too late
187}
Fix

Apply the Checks-Effects-Interactions pattern: update balances[msg.sender] before the external call. Alternatively add a nonReentrant modifier from OpenZeppelin's ReentrancyGuard.

High ACC-02 Missing access control on transferOwnership() Access.sol:92

transferOwnership() is callable by any address. An attacker can immediately become the contract owner and drain protocol funds or pause the system. SWC-105.

Fix

Add onlyOwner modifier. Use OpenZeppelin's Ownable2Step for two-step ownership transfer with confirmation to prevent accidental transfers.

High ARITH-01 Unchecked arithmetic in reward accumulator Vault.sol:241

Reward accumulation uses an unchecked block. With large enough token balances this silently wraps, zeroing accumulated rewards and permanently blocking user withdrawals.

Fix

Remove the unchecked block or add explicit overflow guards. Solidity ≥0.8 checks by default — only use unchecked for provably safe loop counters.

High ORCL-01 Single-block spot price oracle — manipulable Vault.sol:317

Collateral pricing uses a single Uniswap V2 spot price read. A flash loan sandwich attack can manipulate this within a single block, inflating collateral value and draining the lending pool.

Fix

Use a time-weighted average price (TWAP) over at least 30 minutes, or integrate a Chainlink price feed as a secondary source with circuit-breaker logic.

Medium EXT-03 Unchecked external call return value Vault.sol:198

Return value of a low-level .call() is discarded. Silent failures allow the function to continue execution as if the call succeeded, potentially leaving state inconsistent.

Fix

Always check the boolean return: (bool ok,) = addr.call{...}(""); require(ok, "call failed");

Info GAS-01 Redundant SLOAD in loop — gas optimisation Vault.sol:276

A storage variable is read inside a loop on every iteration. Cache it in a local memory variable before the loop to reduce gas cost by ~2100 gas per iteration.

Info STYLE-01 Missing NatSpec on public functions Vault.sol · 6 functions

Public and external functions are missing NatSpec documentation (@notice, @param, @return). Not a vulnerability but reduces auditability and user trust.

Findings are representative. Real results appear after your first scan.

v3.27.0 · findings