58357 sc low permanent freezing of tokeautoeth strategy rewards in myt vault
Submitted on Nov 1st 2025 at 15:21:56 UTC by @call_me_rp for Audit Comp | Alchemix V3
Report ID: #58357
Report Type: Smart Contract
Report severity: Low
Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/strategies/mainnet/TokeAutoEth.sol
Impacts:
Permanent freezing of unclaimed royalties
Permanent freezing of unclaimed yield
Description
Summary
Rewards generated by the TokeAutoEth strategy are claimed into the MYT vault (address(MYT)). Once received or staked under the MYT address, these rewards (TOKE token) cannot be withdrawn, transferred, or reallocated. As a result, all rewards are permanently stuck in the MYT contract.
Description
When claimRewards() is called, the strategy executes:
MYTStrategy.sol::
function claimRewards() public virtual returns (uint256) {
require(!killSwitch, "emergency");
_claimRewards();
}
It calls into TokeAutoEth.sol::
function _claimRewards() internal override returns (uint256 rewardsClaimed) {
rewardsClaimed = rewarder.earned(address(this));
>> rewarder.getReward(address(this), address(MYT), false); // transfer all TOKE token rewards to morpho vault or get staked on myt address
}
The Tokemak rewarder then either transfers the TOKE tokens or stakes them with recipient = address(MYT):
[Link to Tokemak rewarder code]](https://github.com/Tokemak/v2-core-pub/blob/de163d5a1edf99281d7d000783b4dc8ade03591e/src/rewarders/AbstractRewarder.sol#L306C4-L331C6)
Since the MYT vault has no functionality to transfer, withdraw, or re-allocate these TOKE rewards, all claimed rewards becomes permanently locked.
Additionally, anyone can call claimRewards(), meaning the freeze can occur at any time, even if rewards are small and unintended.
Impact
All TOKE rewards generated by the strategy become locked into myt.
Recommendation
Claim rewards to the strategy instead of the MYT vault:
rewarder.getReward(address(this), address(this), false);
Then implement appropriate handling in the strategy:
Optionally swap to underlying asset, OR sends to owner
Introduce unstake() too to get staked toke.
Proof of Concept
Proof of Concept
PoC Summary
Since the real rewarder contract on mainnet distributes rewards based on live protocol state, the test environment cannot naturally reproduce accrued rewards. To demonstrate the issue in isolation, we replaced the rewarder contract implementation at its address using vm.etch and pointed its rewardToken storage slot to a mock ERC20 token. The mock rewarder is intentionally minimal and always returns a fixed reward amount (5e18) for earned() and sends that amount in getReward().
By doing this, we simulate the presence of claimable rewards without altering the whole rewarder logic. When claimRewards() is executed, the adapter puts recipient as myt, and then those reward token(TOKE token) will always stuck in vault/MYT.
Add below test case and interfaces into
TokeAutoEthStrategy.t.sol:
run by
forge test --mt test_rewards_stuck_into_myt -vvvvoutput:
Was this helpful?