Submitted by kenzo, also found by 0x52, ElKu, hansfriese, hyh, and panprog
https://github.com/code-423n4/2022-07-fractional/blob/main/src/modules/Migration.sol#L308
https://github.com/code-423n4/2022-07-fractional/blob/main/src/modules/Migration.sol#L321
https://github.com/code-423n4/2022-07-fractional/blob/main/src/modules/Migration.sol#L312
https://github.com/code-423n4/2022-07-fractional/blob/main/src/modules/Migration.sol#L325
When a user calls withdrawContribution, it will try to send him back his original contribution for the proposal.
But if the proposal has been committed, and other users have interacted with the buyout, Migration will receive back a different amount of ETH and tokens.
Therefore it shouldnt send the user back his original contribution, but should send whatever his share is of whatever was received back from Buyout.
Loss of funds for users.
Some users might not be able to withdraw their contribution at all,
and other users might withdraw funds that belong to other users. (This can also be done as a purposeful attack.)
A summary is described at the top.
Its probably not needed, but heres the flow in detail.
When a user joins a proposal, Migration saves his contribution:
Later when the user would want to withdraw his contribution from a failed migration, Migration would refer to these same variables to decide how much to send to the user:
But if the proposal was committed, and other users interacted with the buyout, then the amount of ETH and tokens that Buyout sends back is not the same contribution.
For example, if another user called buyFractions for the buyout, it will decrease the amount of tokens in the pool:
And when the proposal will end, if it has failed, Buyout will send back to Migration the amount of tokens in the pool:
(**Same will happen for the ETH amount)
Therefore, Migration will receive back less tokens than the original contribution.
When the user will try to call withdrawContribution to withdraw his contribution from the pool, Migration would try to send the users original contribution.
But theres a deficit of that.
If other users have contributed the same token, then it will transfer their tokens to the user.
If not, then the withdrawal will simply revert for insufficient balance.
I am not sure, but I think that the correct solution would be that upon a failed proposals end, there should be a hook call from Buyout to the proposer - in our situation, Migration.
Migration would then see(/receive as parameter) how much ETH/tokens were received, and update the proposal with the change needed. eg. send to each user 0.5 his tokens and 1.5 his ETH.
In another issue I submitted, User cant withdraw assets from failed migration if another buyout is going on/succeeded, I described for a different reason why such a callback to Migration might be needed. Please see there for more implementation suggestions.
I think this issue shows that indeed it is needed.
stevennevins (Fractional) confirmed 
HardlyDifficult (judge) commented:
