Omniscia Steadefi Audit

TraderJoeYieldFarmReader Manual Review Findings

TraderJoeYieldFarmReader Manual Review Findings

TJF-01M: Inexplicable Delta Return

TypeSeverityLocation
Logical FaultTraderJoeYieldFarmReader.sol:L140

Description:

The TraderJoeYieldFarmReader::delta function returns an arbitrary delta evaluation that does not appear to be base 1e18 as the zero-value conditional within it yields 1 instead of 1e18.

Impact:

While the code is incorrect as it yields 1 when the _tokenAAmt and _tokenADebtAmt values are 0, its impact cannot be assessed as it is not in use within the codebase.

Example:

contracts/vaults/trader-joe/TraderJoeYieldFarmReader.sol
132/**
133 * Current delta: token A equity value / vault's equityValue; possible to be negative value
134 * @return delta Current delta in 1e18
135*/
136function delta() public view returns (int) {
137 (uint256 _tokenAAmt,) = manager.assetInfo();
138 (uint256 _tokenADebtAmt,) = manager.debtInfo();
139
140 if (_tokenAAmt == 0 && _tokenADebtAmt == 0) return 1;
141
142 return (int(_tokenAAmt) - int(_tokenADebtAmt))
143 * int(to18ConversionFactor(tokenA()))
144 * int(priceOracle.consult(tokenA()))
145 / int(equityValue());
146}

Recommendation:

We advise more documentation to be introduced for the TraderJoeYieldFarmReader::delta function, such as its expected usage as well as why only TraderJoeYieldFarmReader::tokenA is considered in its calculations. Additionally, we advise the return statement to yield either 0 or 1e8 instead of 1 as a "delta" of 1 is incorrect.

Alleviation (4325253d6de0ea91c1e9fb9e01d2e7e98f3d83a9):

The function correctly yields 0 when the token A debt and asset amounts are zero in the latest implementation, addressing the exhibit's highlighted ambiguity.

TJF-02M: Potentially Incorrect Default Values

TypeSeverityLocation
Logical FaultTraderJoeYieldFarmReader.sol:L128, L154

Description:

The default values yielded whenever either of the variables utilized in the respective divisions is zero appears to be incorrect as it is always zero even when the denominator of the division is zero.

Impact:

The impact of this exhibit cannot be assessed as it depends on how the relevant data points are utilized.

Example:

contracts/vaults/trader-joe/TraderJoeYieldFarmReader.sol
148/**
149 * Debt ratio: token A and token B debt value / total asset value
150 * @return debtRatio Current debt ratio % in 1e18
151*/
152function debtRatio() public view returns (uint256) {
153 (uint256 tokenADebtValue, uint256 tokenBDebtValue) = debtValue();
154 if (assetValue() == 0) return 0;
155 return (tokenADebtValue + tokenBDebtValue) * SAFE_MULTIPLIER / assetValue();
156}

Recommendation:

We advise the return statements to yield "infinity" (type(uint256).max) when the denominator is zero, representing that the system is in a significantly abnormal state (i.e. a non-zero TraderJoeYieldFarmReader::debtValue and a zero TraderJoeYieldFarmReader::assetValue).

Alleviation (4325253d6de0ea91c1e9fb9e01d2e7e98f3d83a9):

The Steadefi team evaluated this exhibit and outlined that the likelihood of a non-zero debt when the TraderJoeYieldFarmReader::assetValue evaluates to 0 is highly improbable, rendering the exhibit's rationale incorrect. As such, we consider this exhibit nullified.

TJF-03M: Unsafe Casting Operations

TypeSeverityLocation
Mathematical OperationsTraderJoeYieldFarmReader.sol:L142, L145

Description:

The referenced statements perform a casting operation from the uint256 data type to the int256 data type which is unsafe.

Impact:

Unsafe casting operations can result in normally positive variables to become negative, significantly affecting all relevant arithmetic operations.

Example:

contracts/vaults/trader-joe/TraderJoeYieldFarmReader.sol
132/**
133 * Current delta: token A equity value / vault's equityValue; possible to be negative value
134 * @return delta Current delta in 1e18
135*/
136function delta() public view returns (int) {
137 (uint256 _tokenAAmt,) = manager.assetInfo();
138 (uint256 _tokenADebtAmt,) = manager.debtInfo();
139
140 if (_tokenAAmt == 0 && _tokenADebtAmt == 0) return 1;
141
142 return (int(_tokenAAmt) - int(_tokenADebtAmt))
143 * int(to18ConversionFactor(tokenA()))
144 * int(priceOracle.consult(tokenA()))
145 / int(equityValue());
146}

Recommendation:

We advise the code to perform the casting operations safely, preferably via the usage of a library such as SafeCast by OpenZeppelin. To note, the usage of a 0.8.X compiler with built-in safe arithmetics does not cover casting operations which still need to be manually validated**.

If the usage of a library is undesirable, we advise the casting statements to be accompanied by require checks that ensure the casted values are less-than-or-equal to the maximum an int256 variable can hold (type(int256).max).

Alleviation (4325253d6de0ea91c1e9fb9e01d2e7e98f3d83a9):

The calculations were significantly simplified, performing a single casting operation at the end of the calculation chain optimally and securely.