MEDIUM severity: The vulnerability, AutoRoller#eject, allows an attacker to steal the yield from all yield tokens (YT. The vulnerability, AutoRoller#eject, allows an attacker to steal the yield from all yield tokens (YTs) in the system. This is achieved by exploiting the combination of the user's share of the pool tokens (PTs) and YTs, which inadvertently sends the attacker the entire target balance of the contract,...

Vulnerable code:
```\nfunction eject(\n    uint256 shares,\n    address receiver,\n    address owner\n) public returns (uint256 assets, uint256 excessBal, bool isExcessPTs) {\n    (excessBal, isExcessPTs) = _exitAndCombine(shares);\n\n    _burn(owner, shares);\n\n    if (isExcessPTs) {\n        pt.transfer(receiver, excessBal);\n    } else {\n        yt.transfer(receiver, excessBal);\n    }\n\n    assets = asset.balanceOf(address(this));\n    asset.transfer(receiver, assets);\n\n    emit Ejected(msg.sender, receiver, owner, assets, shares, \n        isExcessPTs? excessBal : 0, \n        isExcessPTs? 0 : excessBal\n    );\n}\n\nfunction _exitAndCombine(uint256 shares) internal returns (uint256, bool) {\n    uint256 supply = totalSupply;\n\n    uint256 lpBal = shares.mulDivDown(space.balanceOf(address(this)), supply);\n    uint256 totalPTBal = pt.balanceOf(address(this));\n    uint256 ptShare = shares.mulDivDown(totalPTBal, supply);\n\n    uint256 ytBal = shares.mulDivDown(yt.balanceOf(address(this)), supply);\n    ptShare += pt.balanceOf(address(this)) - totalPTBal;\n\n    unchecked {\n        if (ptShare > ytBal) {\n            divider.combine(address(adapter), maturity, ytBal);\n            return (ptShare - ytBal, true);\n        } else {\n            divider.combine(address(adapter), maturity, ptShare);\n            return (ytBal - ptShare, false);\n        }\n    }\n}\n```\n```\nfunction combine(\n    address adapter,\n    uint256 maturity,\n    uint256 uBal\n) external nonReentrant whenNotPaused returns (uint256 tBal) {\n    if (!adapterMeta[adapter].enabled) {\n        revert Errors.InvalidAdapter();\n    }\n    if (!_exists(adapter, maturity)) {\n        revert Errors.SeriesDoesNotExist();\n    }\n\n    uint256 level = adapterMeta[adapter].level;\n    if (level.combineRestricted() && msg.sender!= adapter) {\n        revert Errors.CombineRestricted();\n    }\n\n    // Burn the PT\n    Token(series[adapter][maturity].pt).burn(msg.sender, uBal);\n\n    uint256 collected = _collect(msg.sender, adapter, maturity, uBal, uBal, address(0));\n\n    // Convert from units of Underlying to units of Target\n    tBal = uBal / cscale;\n    ERC20(Adapter(adapter).target()).safeTransferFrom(adapter, msg.sender, tBal);\n\n    // Notify only when Series is not settled as when it is, the _collect() call above would trigger a _redeemYT which will call notify\n    if (!settled) {\n        Adapter(adapter).notify(msg.sender, tBal, false);\n    }\n    unchecked {\n        // Safety: bounded by the Target's total token supply\n        tBal += collected;\n    }\n    emit Combined(adapter, maturity, tBal, msg.sender);\n}\n```\n```\nfunction _collect(\n    address usr,\n    address adapter,\n    uint256 maturity,\n    uint256 uBal,\n    uint256 uBalTransfer,\n    address to\n) internal returns (uint256 collected) {\n    if (!_exists(adapter, maturity)) {\n        revert Errors.SeriesDoesNotExist();\n    }\n\n    if (!adapterMeta[adapter].enabled &&!_settled(adapter, maturity)) {\n        revert Errors.InvalidAdapter();\n    }\n\n    Series memory _series = series[adapter][maturity];\n    uint256 lscale = lscales[adapter][maturity][usr];\n\n    uint256 tBalNow = uBal / _series.maxscale; // preventive round-up towards the protocol\n    uint256 tBalPrev = uBal / lscale;\n    unchecked {\n        collected = tBalPrev > tBalNow? tBalPrev - tBalNow : 0;\n    }\n\n    ERC20(Adapter(adapter).target()).safeTransferFrom(adapter, usr, collected);\n    Adapter(adapter).notify(usr, collected, false); // Distribute reward tokens\n}\n```