Platform: Code4rena
Start Date: 12/04/2023
Pot Size: $60,500 USDC
Total HM: 21
Participants: 199
Period: 7 days
Judge: hansfriese
Total Solo HM: 5
Id: 231
League: ETH
Rank: 69/199
Findings: 3
Award: $50.95
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: decade
Also found by: 0x3b, 0xDACA, 0xWaitress, 0xWeiss, 0xkaju, Arz, Aymen0909, BPZ, EloiManuel, HaCk0, J4de, Jerry0x, Jiamin, John, Juntao, Kek, Lalanda, MiloTruck, Mukund, PNS, RedTiger, Ruhum, Satyam_Sharma, ToonVH, Tricko, Udsen, ak1, anodaram, bin2chen, carrotsmuggler, cccz, circlelooper, deadrxsezzz, giovannidisiena, jasonxiale, joestakey, juancito, karanctf, kenta, kodyvim, ladboy233, lil_eth, lukino, markus_ether, marwen, mrpathfindr, nobody2018, parlayan_yildizlar_takimi, peakbolt, ravikiranweb3, rbserver, rvierdiiev, silviaxyz, volodya, zhuXKET, zzebra83
0.0748 USDC - $0.07
Equity.sol#restructureCapTable:https://github.com/code-423n4/2023-04-frankencoin/blob/main/contracts/Equity.sol#L309-L316
RestructureCaptable is a function to use in case of disaster like scenario where there are less than 1000 zchf in equity left. The idea of this function is for a small group of FPS holders to "save" the project. But this function is malformed and would hurt a single user or revert in case he/she would not own enough amount of zchf
function restructureCapTable(address[] calldata helpers, address[] calldata addressesToWipe) public { require(zchf.equity() < MINIMUM_EQUITY); checkQualified(msg.sender, helpers); // check 3% for (uint256 i = 0; i<addressesToWipe.length; i++){ address current = addressesToWipe[0]; //@audit-issue replace to addressToWipe[i] _burn(current, balanceOf(current)); } }
VS Code
Replace the code
function restructureCapTable(address[] calldata helpers, address[] calldata addressesToWipe) public { require(zchf.equity() < MINIMUM_EQUITY); checkQualified(msg.sender, helpers); // check 3% for (uint256 i = 0; i<addressesToWipe.length; i++){ + address current = addressesToWipe[i]; - address current = addressesToWipe[0]; _burn(current, balanceOf(current)); } }
#0 - c4-pre-sort
2023-04-20T14:27:19Z
0xA5DF marked the issue as duplicate of #941
#1 - c4-judge
2023-05-18T14:25:37Z
hansfriese marked the issue as satisfactory
🌟 Selected for report: Josiah
Also found by: 0xDACA, Diana, Emmanuel, Kumpa, Nyx, RaymondFam, Ruhum, __141345__, bin2chen, carlitox477, lil_eth, nobody2018, rbserver
28.2764 USDC - $28.28
Position.sol#reduceLimitForClone : https://github.com/code-423n4/2023-04-frankencoin/blob/main/contracts/Position.sol#L97-L101
Line 89 and line 90 of Position.sol it is written as a comment :
“Adjust this position's limit to give away half of the remaining limit to the clone. Invariant: global limit stays the same. “
But it’s false, I will explain why.
When cloning a position (which seems to be the easiest way to acquire a position), the limit of zchf that can be minted by the primary position is affected, here is the process :
clonePosition()
from MintingHub.soluint256 limit = existing.reduceLimitForClone(_initialMint);
position.sol#reduceLimitForClone(uint256 _minimum)
:uint256 reduction = (limit - minted - _minimum)/2; limit -= reduction + _minimum; // new limit for positionA = 9500 return reduction + _minimum; // limit for clone = 18 000
| limitA | 20000 | | --- | --- | | currentMintA | 1000 | | minimumB | 2000 | | reduction | 8500 | | newlimitA | 9500 | | limitCloneB | 18000 |
⇒ UserA who deposited a collateral according to its mintingMaximum capacity to not be challenged even if he/she reach the limit will have it’s new limit hugely reduced (by more than average in this example)
⇒ UserB who will deposit according to it’s _initialMint amount will have a limit hugely higher than wanted ( more than 8x in example) and is at risk to be challenged because its collaretal is not in accordance with it’s cloning position limit
To conclude it can be dangerous if userB mints more than he wanted at the beginning, its position is valid as he clones a valid one but he can mint a lot more than intended at the beginning, userA will have to creates another positon and repay fees to mint the amount he wanted at the beginning
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
VS Code
Add a parameter in the MintingHub.sol#clonePosition that ask cloner which limit he wants to reach, do your calculs and if limitwanted < existing.reduceLimitForClone(_initialMint); , clone the position with limitWanted as a limit and only reduce the limit of limitPositionA - limitwanted
#0 - c4-pre-sort
2023-04-22T14:48:24Z
0xA5DF marked the issue as duplicate of #932
#1 - 0xA5DF
2023-04-22T14:48:28Z
Didn't fully identify the impact
#2 - c4-pre-sort
2023-04-22T14:48:37Z
0xA5DF marked the issue as low quality report
#3 - c4-judge
2023-05-18T14:00:09Z
hansfriese marked the issue as satisfactory