minting in onTokenTransfer handles the case equity <= amount as the first deposit, minting it 1000 shares no matter the amount of ZCHF transferred
File: Equity.sol
244: require(equity >= MINIMUM_EQUITY, "insuf equity"); // ensures that the initial deposit is at least 1000 ZCHF
245:
246: // Assign 1000 FPS for the initial deposit, calculate the amount otherwise
247: uint256 shares = equity <= amount ? 1000 * ONE_DEC18 : calculateSharesInternal(equity - amount, amount);
The issue is that there is another case scenario in which equity <= amount: if a position is opened on mintingHub, which increases equity by transferring zchf to the reserve:
Lines of code
https://github.com/code-423n4/2023-04-frankencoin/blob/1022cb106919fba963a89205d3b90bf62543f68f/contracts/Equity.sol#L268 https://github.com/code-423n4/2023-04-frankencoin/blob/1022cb106919fba963a89205d3b90bf62543f68f/contracts/MintingHub.sol#L108 https://github.com/code-423n4/2023-04-frankencoin/blob/1022cb106919fba963a89205d3b90bf62543f68f/contracts/Equity.sol#L268
Vulnerability details
minting in
onTokenTransfer
handles the caseequity <= amount
as the first deposit, minting it1000
shares no matter the amount ofZCHF
transferredThe issue is that there is another case scenario in which
equity <= amount
: if a position is opened onmintingHub
, which increases equity by transferringzchf
to the reserve:Impact
If a position is opened before
Equity
shares have started to be minted, the following scenario can happen:Frankencoin
is deployedsuggestMinter()
openPosition
to open a position - note that this can be done instantly, there is no waiting time to open a position.zchf
.zchf.transferAndCall(address(zchf.reserve()), 0, "")
equity.totalSupply == 0
,newTotalShares
is set as1000e18
here1000 FPS
without having transferred anyzchf
. He will be able to redeem it againstzchf
in the future, stealing from otherFPS
holdersProof Of Concept
Run the test
test_Audit_Equity_FreeShares
in the following gist: https://gist.github.com/joestakey/fbc954de53b7e018f5121212488e847cThis shows the steps enounced above, and should result in:
Tools Used
Manual Analysis
Mitigation
onTokenTransfer
should be refactored to revert ifamount <= 1000
whentotalSupply == 0