Stratax Contracts

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

Stale `IStratax` Interface Causes Function Selector Mismatches On Multiple Functions

Author Revealed upon completion

The IStratax interface in src/interfaces/internal/IStratax.sol is intended to define the external API of the Stratax contract, as stated in its NatSpec: "This interface defines all external and public functions for the Stratax contract." However, the Stratax contract does not declare is IStratax (it only declares contract Stratax is Initializable), so the Solidity compiler does not enforce signature consistency between the two. The interface has drifted from the implementation, producing different 4-byte function selectors for at least three functions and divergent struct definitions for two structs. The specific mismatches are as follows.

The unwindPosition() function in the interface declares five parameters (address, address, uint256, bytes, uint256), while the implementation declares six parameters (address, uint256, address, uint256, bytes, uint256), adding a _collateralToWithdraw parameter and reordering the rest. These different canonical signatures produce different selectors, so any call through the interface reverts.

// Interface (src/interfaces/internal/IStratax.sol)
function unwindPosition(
address _collateralToken,
address _debtToken,
// @audit missing _collateralToWithdraw parameter
uint256 _debtAmount,
bytes calldata _oneInchSwapData,
uint256 _minReturnAmount
) external;
// @audit selector: unwindPosition(address,address,uint256,bytes,uint256)
// Implementation (src/Stratax.sol)
function unwindPosition(
address _collateralToken,
uint256 _collateralToWithdraw, // @audit extra parameter not in interface
address _debtToken,
uint256 _debtAmount,
bytes calldata _oneInchSwapData,
uint256 _minReturnAmount
) external onlyOwner {
// @audit selector: unwindPosition(address,uint256,address,uint256,bytes,uint256)

The interface declares calculateParams(TradeDetails) but the implementation names the function calculateOpenParams(TradeDetails). Different function names produce different selectors regardless of the parameter types.

// Interface
function calculateParams(TradeDetails memory details) // @audit wrong function name
external view returns (uint256 flashLoanAmount, uint256 borrowAmount);
// Implementation
function calculateOpenParams(TradeDetails memory details) // @audit actual function name
public view returns (uint256 flashLoanAmount, uint256 borrowAmount)

The interface declares function BASIS_POINTS() external view returns (uint256) but the implementation defines uint256 public constant FLASHLOAN_FEE_PREC = 10000. The auto-generated getter for FLASHLOAN_FEE_PREC has a different selector from BASIS_POINTS().

Additionally, two struct definitions diverge between the interface and implementation. The interface TradeDetails has seven fields starting with uint256 ltv, while the implementation has eight fields starting with address collateralToken, address borrowToken and omits ltv. The interface UnwindParams has five fields, while the implementation has six fields including uint256 collateralToWithdraw. Even if function names and parameter counts matched, ABI encoding using the interface struct layouts would produce incorrect calldata.

This issue has a medium impact because the mismatches would cause unconditional reverts for any integrating contract or frontend that uses the IStratax interface to interact with the Stratax contract. However, the unwindPosition() function is restricted by the onlyOwner modifier, limiting who can call it, and direct callers who build calldata from the contract ABI (rather than the interface) are unaffected.

This issue has a low likelihood because the IStratax interface is not currently imported, referenced, or used anywhere in the codebase -- not in the Stratax contract itself, not in tests, and not in any other contract. The interface resides in an internal subdirectory, further reducing the probability that external integrators would adopt it. While it is plausible that a future integrator could use this interface, there is no evidence of current or planned usage.

recommendation

Update IStratax to exactly match the Stratax implementation's function signatures, struct definitions, and constant names. Specifically, update the unwindPosition() signature to include the _collateralToWithdraw parameter in the correct position, rename calculateParams() to calculateOpenParams(), rename BASIS_POINTS() to FLASHLOAN_FEE_PREC(), update both the TradeDetails and UnwindParams structs to match the implementation, and add the missing getMaxLeverage(address), calculateUnwindParams(address, address), and aaveDataProvider() functions. Declare contract Stratax is Initializable, IStratax so the Solidity compiler enforces signature consistency at compile time and prevents future drift.

Support

FAQs

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

Give us feedback!