# Foundation recall will inflate governance power for earnest voters

Bug Deep Dive #5 · 1 December 2025

Bug Deep Dives · [The Contest Academy](https://0xsimao.com/the-contest-academy) · 0xSimao

---

| Title | Foundation recall will inflate governance power for earnest voters |
| Reward | $381, 14 dups |
| Contest | Summer.fi - 29 Sep 2025 on Sherlock |
| Author | Elroi |
| Context | Wrong variable tracking |

This is a straightforward example of functionality the protocol overlooked. It is often a trivial finding, but it touches business logic, so many people miss it.

The `SummerVestingWalletEscrow` mints xSUMR (governance power) when a user stakes, and locks the tokens in their `SummerVestingWallet`.

```solidity
function _stakeFromFactory(
    IMinimalVestingFactory _vestingFactory,
    address _user
) internal {
    // Prevent double-staking same factory to preserve invariant on accounting maps
    address factoryAddress = address(_vestingFactory);
    if (
        _userStakedVestingFactoriesBalance[_user].contains(factoryAddress)
    ) {
        revert Staking_FactoryAlreadyStaked();
    }

    // Resolve vesting wallet and validate escrow ownership
    // vestingWallets map can't be modified, always keeps the original owner
    address vestingWallet = _vestingFactory.vestingWallets(_user);
    if (vestingWallet == address(0)) {
        revert Staking_InvalidAddress("Vesting wallet not found");
    }

    _validateVestingWalletOwner(vestingWallet);

    // Snapshot SUMR balance and released amount at time of stake
    uint256 balance = SUMMER_TOKEN.balanceOf(vestingWallet);
    if (balance == 0) {
        revert Staking_ZeroBalance();
    }
    uint256 released = IMinimalVestingWallet(vestingWallet).released(
        address(SUMMER_TOKEN)
    );

    // Persist stake metadata for this user/factory pair
    _userStakedVestingFactoriesBalance[_user].set(factoryAddress, balance);
    _userStakedVestingFactoriesReleased[_user].set(
        factoryAddress,
        released
    );

    // Mint governance power (xSUMR) equal to vesting wallet SUMR balance
    STAKED_SUMMER_TOKEN.mint(_user, balance);

    emit StakedVestingWallet(_user, factoryAddress, balance, released);
}
```

However, `SummerVestingWallet` offers the option to withdraw all the tokens, while the user keeps the governance tokens that were minted — which are then left unbacked.

```solidity
function recallUnvestedTokens() external onlyFactoryOwner {
    if (isRecalled) {
        revert TokensAlreadyRecalled();
    }

    // Get ALL tokens from this wallet - no calculations needed
    uint256 totalBalance = IERC20(token).balanceOf(address(this));

    // Brick the wallet permanently
    isRecalled = true;

    // Transfer ALL tokens to admin (vested + unvested = everything)
    if (totalBalance > 0) {
        IERC20(token).safeTransfer(msg.sender, totalBalance);
    }

    emit UnvestedTokensRecalled(totalBalance);
}
```

**Conclusion**

This finding would earn you **\$381**, which is fair since it is very simple: the protocol team completely overlooked the governance tokens left in circulation.

[**Full Report**](https://audits.sherlock.xyz/contests/1176/report)

---

Newer: [Unfair distribution of rewards for LPs](https://0xsimao.com/the-contest-academy/bug-deep-dive-6) · Older: [Satellite chains can't execute onlyGovernance functions](https://0xsimao.com/the-contest-academy/bug-deep-dive-4)
