Stratax Contracts

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

Interface-Implementation Mismatches Break External Composability

Author Revealed upon completion

Interface-Implementation Mismatches Break External Composability

Description

  • Multiple critical mismatches exist between the IStratax interface and the Stratax implementation. These are not minor documentation issues — they result in different function selectors, meaning any contract using IStratax to call Stratax will revert.

Mismatch 1 — unwindPosition: Different parameter count (5 vs 6), different selector:

// IStratax.sol:124-130 — 5 parameters
function unwindPosition(
address _collateralToken,
address _debtToken, // <-- param #2 is address
uint256 _debtAmount,
bytes calldata _oneInchSwapData,
uint256 _minReturnAmount
) external;
// Stratax.sol:236-243 — 6 parameters
function unwindPosition(
address _collateralToken,
uint256 _collateralToWithdraw, // <-- EXTRA param #2 is uint256
address _debtToken, // <-- shifted to param #3
uint256 _debtAmount,
bytes calldata _oneInchSwapData,
uint256 _minReturnAmount
) external onlyOwner;

Mismatch 2 — calculateParams vs calculateOpenParams: Different function names:

// IStratax.sol:194
function calculateParams(TradeDetails memory details) external view returns (...);
// Stratax.sol:380 — DIFFERENT NAME
function calculateOpenParams(TradeDetails memory details) public view returns (...);

Mismatch 3 — TradeDetails struct: Different fields:

// IStratax.sol:34-42
struct TradeDetails {
uint256 ltv; // <-- present in interface
uint256 desiredLeverage;
uint256 collateralAmount;
uint256 collateralTokenPrice;
uint256 borrowTokenPrice;
uint256 collateralTokenDec;
uint256 borrowTokenDec;
}
// Stratax.sol:57-74
struct TradeDetails {
address collateralToken; // <-- DIFFERENT: address fields instead of ltv
address borrowToken; // <-- DIFFERENT: address field
uint256 desiredLeverage;
uint256 collateralAmount;
uint256 collateralTokenPrice;
uint256 borrowTokenPrice;
uint256 collateralTokenDec;
uint256 borrowTokenDec;
}

Mismatch 4 — UnwindParams struct: Different field count:

// IStratax.sol:25-31 — 5 fields (missing collateralToWithdraw)
// Stratax.sol:41-54 — 6 fields (includes collateralToWithdraw)

Mismatch 5 — BASIS_POINTS(): Does not exist in implementation:

// IStratax.sol:204
function BASIS_POINTS() external view returns (uint256);
// Stratax.sol — No such constant. Has FLASHLOAN_FEE_PREC instead

Risk

Likelihood:

  • Any developer or integrator who uses the published IStratax interface will encounter these mismatches immediately

  • Automated integration tools (e.g., ethers.js with IStratax ABI) will generate incorrect calldata

  • The mismatches are deterministic — they will always cause failures

Impact:

  • Complete integration failure: Any smart contract calling IStratax(stratax).unwindPosition(...) will target a non-existent function selector and revert

  • Broken composability: Multi-sig wallets (e.g., Gnosis Safe), automation bots (e.g., Gelato, Chainlink Keepers), and other protocols cannot use the interface

  • Frontend breakage: Frontend SDKs generating transactions from the IStratax ABI will produce invalid transactions

  • Trust erosion: Publishing an incorrect interface signals a lack of testing rigor and may deter integrations

Proof of Concept

How the issue manifests:

  1. A multi-sig wallet owner wants to unwind a position using IStratax

  2. They encode the call as IStratax(strataxProxy).unwindPosition(collateralToken, debtToken, debtAmount, swapData, minReturn) — 5 parameters as per the interface

  3. The encoded calldata targets the function selector keccak256("unwindPosition(address,address,uint256,bytes,uint256)") — a 5-param signature

  4. The actual Stratax contract only recognizes keccak256("unwindPosition(address,uint256,address,uint256,bytes,uint256)") — a 6-param signature

  5. The selectors are different → the call reverts with no matching function

  6. The multi-sig cannot unwind the position using the published interface

PoC code:

function testExploit_InterfaceMismatch() public {
// Compute function selectors
bytes4 interfaceSelector = bytes4(keccak256("unwindPosition(address,address,uint256,bytes,uint256)"));
bytes4 implementationSelector = bytes4(keccak256("unwindPosition(address,uint256,address,uint256,bytes,uint256)"));
// They are DIFFERENT — calls via IStratax will revert
assertTrue(interfaceSelector != implementationSelector, "Selectors should differ");
}

Expected outcome: The function selectors differ, confirming that any call made through the IStratax interface will target a non-existent function on the implementation and revert.

Recommended Mitigation

The root cause is that the interface was written independently and never synchronized after the implementation was modified. The fix must align all function signatures, struct definitions, and constant names.

Primary fix — Synchronize the interface with the implementation:

// IStratax.sol — corrected to match Stratax.sol
struct UnwindParams {
address collateralToken;
uint256 collateralToWithdraw; // ADD missing field
address debtToken;
uint256 debtAmount;
bytes oneInchSwapData;
uint256 minReturnAmount;
}
struct TradeDetails {
address collateralToken; // CHANGE from uint256 ltv
address borrowToken; // ADD missing field
uint256 desiredLeverage;
uint256 collateralAmount;
uint256 collateralTokenPrice;
uint256 borrowTokenPrice;
uint256 collateralTokenDec;
uint256 borrowTokenDec;
}
function unwindPosition(
address _collateralToken,
uint256 _collateralToWithdraw, // ADD missing parameter
address _debtToken,
uint256 _debtAmount,
bytes calldata _oneInchSwapData,
uint256 _minReturnAmount
) external;
function calculateOpenParams(TradeDetails memory details) // RENAME from calculateParams
external view returns (uint256 flashLoanAmount, uint256 borrowAmount);
function FLASHLOAN_FEE_PREC() external view returns (uint256); // RENAME from BASIS_POINTS

Why this works:

  • Aligns function selectors between interface and implementation so calls through IStratax target the correct functions

  • Aligns struct layouts so ABI encoding/decoding produces correct data

  • Renames mismatched constants to match the implementation

Additional recommendation: Consider auto-generating the interface from the implementation contract to prevent future drift. Tools like forge inspect Stratax abi can produce the canonical ABI.

Support

FAQs

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

Give us feedback!