AutoRoller#eject can be used to steal all the yield from vault's YTs
AutoRoller#eject collects all the current yield of the YTs, combines the users share of the PTs and YTs then sends the user the entire target balance of the contract. The problem is that combine claims the yield for ALL YTs, which sends the AutoRoller target assets. Since it sends the user the entire target balance of the contract it accidentally sends the user the yield from all the pool's YTs.\\n```\\nfunction eject(\\n    uint256 shares,\\n    address receiver,\\n    address owner\\n) public returns (uint256 assets, uint256 excessBal, bool isExcessPTs) {\\n\\n    // rest of code\\n\\n    //@audit call of interest\\n    (excessBal, isExcessPTs) = _exitAndCombine(shares);\\n\\n    _burn(owner, shares); // Burn after percent ownership is determined in _exitAndCombine.\\n\\n    if (isExcessPTs) {\\n        pt.transfer(receiver, excessBal);\\n    } else {\\n        yt.transfer(receiver, excessBal);\\n    }\\n\\n    //@audit entire asset (adapter.target) balance transferred to caller, which includes collected YT yield and combined\\n    asset.transfer(receiver, assets = asset.balanceOf(address(this)));\\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; // Save extra SLOAD.\\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    // rest of code\\n\\n    uint256 ytBal = shares.mulDivDown(yt.balanceOf(address(this)), supply);\\n    ptShare += pt.balanceOf(address(this)) - totalPTBal;\\n\\n    unchecked {\\n        // Safety: an inequality check is done before subtraction.\\n        if (ptShare > ytBal) {\\n\\n            //@audit call of interest\\n            divider.combine(address(adapter), maturity, ytBal);\\n            return (ptShare - ytBal, true);\\n        } else { // Set excess PTs to false if the balances are exactly equal.\\n            divider.combine(address(adapter), maturity, ptShare);\\n            return (ytBal - ptShare, false);\\n        }\\n    }\\n}\\n```\\n\\nEject allows the user to leave the liquidity pool by withdrawing their liquidity from the Balancer pool and combining the PTs and YTs via divider.combine.\\n```\\nfunction combine(\\n    address adapter,\\n    uint256 maturity,\\n    uint256 uBal\\n) external nonReentrant whenNotPaused returns (uint256 tBal) {\\n    if (!adapterMeta[adapter].enabled) revert Errors.InvalidAdapter();\\n    if (!_exists(adapter, maturity)) revert Errors.SeriesDoesNotExist();\\n\\n    uint256 level = adapterMeta[adapter].level;\\n    if (level.combineRestricted() && msg.sender != adapter) revert Errors.CombineRestricted();\\n\\n    // Burn the PT\\n    Token(series[adapter][maturity].pt).burn(msg.sender, uBal);\\n\\n    //@audit call of interest\\n    uint256 collected = _collect(msg.sender, adapter, maturity, uBal, uBal, address(0));\\n\\n    // rest of code\\n\\n    // Convert from units of Underlying to units of Target\\n    tBal = uBal.fdiv(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) Adapter(adapter).notify(msg.sender, tBal, false);\\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\\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)) revert Errors.SeriesDoesNotExist();\\n\\n    if (!adapterMeta[adapter].enabled && !_settled(adapter, maturity)) revert Errors.InvalidAdapter();\\n\\n    Series memory _series = series[adapter][maturity];\\n    uint256 lscale = lscales[adapter][maturity][usr];\\n\\n    // rest of code\\n\\n    uint256 tBalNow = uBal.fdivUp(_series.maxscale); // preventive round-up towards the protocol\\n    uint256 tBalPrev = uBal.fdiv(lscale);\\n    unchecked {\\n        collected = tBalPrev > tBalNow ? tBalPrev - tBalNow : 0;\\n    }\\n\\n    //@audit adapter.target is transferred to AutoRoller\\n    ERC20(Adapter(adapter).target()).safeTransferFrom(adapter, usr, collected);\\n    Adapter(adapter).notify(usr, collected, false); // Distribute reward tokens\\n\\n    // rest of code\\n}\\n```\\n\\nInside divider#combine the collected yield from the YTs are transferred to the AutoRoller. The AutoRoller balance will now contain both the collected yield of the YTs and the target yielded by combining. The end of eject transfers this entire balance to the caller, effectively stealing the yield of the entire AutoRoller.
Combine returns the amount of target yielded by combining the PT and YT. This balance is the amount of assets that should be transferred to the user.
User funds given to the wrong person
```\\nfunction eject(\\n    uint256 shares,\\n    address receiver,\\n    address owner\\n) public returns (uint256 assets, uint256 excessBal, bool isExcessPTs) {\\n\\n    // rest of code\\n\\n    //@audit call of interest\\n    (excessBal, isExcessPTs) = _exitAndCombine(shares);\\n\\n    _burn(owner, shares); // Burn after percent ownership is determined in _exitAndCombine.\\n\\n    if (isExcessPTs) {\\n        pt.transfer(receiver, excessBal);\\n    } else {\\n        yt.transfer(receiver, excessBal);\\n    }\\n\\n    //@audit entire asset (adapter.target) balance transferred to caller, which includes collected YT yield and combined\\n    asset.transfer(receiver, assets = asset.balanceOf(address(this)));\\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; // Save extra SLOAD.\\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    // rest of code\\n\\n    uint256 ytBal = shares.mulDivDown(yt.balanceOf(address(this)), supply);\\n    ptShare += pt.balanceOf(address(this)) - totalPTBal;\\n\\n    unchecked {\\n        // Safety: an inequality check is done before subtraction.\\n        if (ptShare > ytBal) {\\n\\n            //@audit call of interest\\n            divider.combine(address(adapter), maturity, ytBal);\\n            return (ptShare - ytBal, true);\\n        } else { // Set excess PTs to false if the balances are exactly equal.\\n            divider.combine(address(adapter), maturity, ptShare);\\n            return (ytBal - ptShare, false);\\n        }\\n    }\\n}\\n```\\n