Stratax Contracts

First Flight #57
Beginner FriendlyDeFi
100 EXP
Submission Details
Impact: low
Likelihood: medium

L01. Zero _borrowAmount and _flashLoanAmount Accepted

Author Revealed upon completion

Root + Impact

Description

  • createLeveragedPosition validates that _collateralAmount > 0 but applies no equivalent check to _borrowAmount or _flashLoanAmount. Both can be zero, bypassing the core economic invariants of the leveraged position mechanism.

  • When both are zero, the protocol initiates a zero-amount Aave flash loan, supplies user collateral without taking leverage, and the swap checks pass trivially — creating an unlevered Aave deposit that still costs the user gas and flash loan fees.

// src/Stratax.sol:322-339
function createLeveragedPosition(
address _flashLoanToken,
uint256 _flashLoanAmount,
uint256 _collateralAmount,
address _borrowToken,
uint256 _borrowAmount,
bytes calldata _oneInchSwapData,
uint256 _minReturnAmount
) public onlyOwner {
// @> Only collateralAmount is validated; borrow and flash loan amounts unchecked
require(_collateralAmount > 0, "Collateral Cannot be Zero");
FlashLoanParams memory params = FlashLoanParams({...});
// _flashLoanAmount = 0 is passed directly to Aave
aavePool.flashLoanSimple(address(this), _flashLoanToken, _flashLoanAmount, encodedParams, 0);
}

Risk

Likelihood:

  • Off-chain tooling (frontend, bots) can pass zero values by mistake or as a result of calculation errors; without on-chain guards the contract accepts them silently

  • An operator misconfiguring the borrow calculation could deploy positions with zero leverage while paying flash loan fees

Impact:

  • A zero flash loan with zero borrow creates an Aave supply-only position at gas cost plus any flash loan fee, with no leverage benefit — the user's capital is locked in Aave with no corresponding position created

  • The protocol's event LeveragePositionCreated is emitted with borrowAmount = 0, corrupting off-chain accounting

Proof of Concept

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {Test} from "forge-std/Test.sol";
import {Stratax} from "../../src/Stratax.sol";
import {IERC20} from "forge-std/interfaces/IERC20.sol";
import {ConstantsEtMainnet} from "../Constants.t.sol";
import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
contract ZeroAmountsPocTest is Test, ConstantsEtMainnet {
Stratax stratax;
address owner = address(0x123);
function setUp() public {
vm.createSelectFork(vm.envString("ETH_RPC_URL"));
Stratax impl = new Stratax();
UpgradeableBeacon beacon = new UpgradeableBeacon(address(impl), address(this));
bytes memory initData = abi.encodeWithSelector(
Stratax.initialize.selector,
AAVE_POOL, AAVE_PROTOCOL_DATA_PROVIDER,
address(0xdead), address(0), address(0)
);
BeaconProxy proxy = new BeaconProxy(address(beacon), initData);
stratax = Stratax(address(proxy));
vm.prank(address(this));
stratax.transferOwnership(owner);
}
function test_zero_borrow_accepted() public {
deal(WETH, owner, 1 ether);
vm.startPrank(owner);
IERC20(WETH).approve(address(stratax), 1 ether);
// @> _flashLoanAmount = 0, _borrowAmount = 0 — no check exists
// Aave V3 reverts internally on zero flash loan, but this depends
// on undocumented Aave behavior rather than protocol-level validation
vm.expectRevert(); // Aave's internal check catches it, not Stratax
stratax.createLeveragedPosition(
WETH,
0, // @> zero flash loan — no Stratax guard
1 ether,
USDC,
0, // @> zero borrow — no Stratax guard
bytes(""),
0
);
vm.stopPrank();
// The revert comes from Aave, not Stratax — Stratax has no protection
// If Aave ever relaxes its zero-amount validation, this opens a silent path
}
}

Recommended Mitigation

Add explicit non-zero checks at the entry point of createLeveragedPosition:

// src/Stratax.sol — createLeveragedPosition
require(_collateralAmount > 0, "Collateral Cannot be Zero");
+ require(_borrowAmount > 0, "Borrow amount Cannot be Zero");
+ require(_flashLoanAmount > 0, "Flash loan amount Cannot be Zero");

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!