M-1: Broken reward accounting in wrapped aToken contract
Summary:
The wrapped aToken contract's reward accounting system is incompatible with the protocol's architecture, leading to lost farming rewards and incorrect reward distribution.
Description:
When users borrow wrapped aTokens from the intermediate vault, rebalanceATokens_CV() unwraps them on the collateral vault so AAVE recognizes the collateral. This leaves the wrapped aToken contract virtually backed rather than physically backed, as the underlying aTokens are held by the collateral vault.
The forked StataToken reward accounting assumes 100% of aTokens remain in the wrapped contract. However, aTokens used for borrowing are held by the collateral vault, which receives their farming rewards.
The contract ERC20AaveLMUpgradeable that is inherited by the wrapped aToken uses the INCENTIVES_CONTROLLER's getAssetIndex() function to determine rewards. When looking at the INCENTIVES_CONTROLLER function code, we can observe that this value is determined using the total value of the aToken.
_getAssetIndex(
rewardData,
IScaledBalanceToken(asset).scaledTotalSupply(),
10 ** _assets[asset].decimals
);
This creates several issues:
- The wrapped contract incorrectly tracks rewards for aTokens it no longer holds
- Collateral vaults receive farming rewards but cannot claim them
- Users claiming rewards from the wrapped contract receive inflated amounts on a first-come-first-serve basis
- Wrapped aTokens lent on the intermediate vault generate rewards that the vault cannot claim
Impact:
Medium. The farming rewards system is broken, resulting in lost rewards and incorrect distributions.
Recommendation:
Remove the current farming reward system from the wrapped aToken contract.
Instead, implement an onlyOwner() function allowing the Twyne admin to claim farming rewards from both the wrapped contract and collateral vaults. Consider redistributing rewards through a simpler system like Merkl that is compatible with intermediate vaults.