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: 36/199
Findings: 3
Award: $252.00
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: carrotsmuggler
Also found by: Ace-30, KIntern_NA, Nyx, bin2chen, cccz, juancito, mahdikarimi, mov, nobody2018
201.1223 USDC - $201.12
https://github.com/code-423n4/2023-04-frankencoin/blob/1022cb106919fba963a89205d3b90bf62543f68f/contracts/MintingHub.sol#L140-L148 https://github.com/code-423n4/2023-04-frankencoin/blob/1022cb106919fba963a89205d3b90bf62543f68f/contracts/MintingHub.sol#L199-L229
The adjustPrice function allows the position owner to frontrun and adjust the price lower when opening a challenge. This may cause the challenger to sell their collateral at a lower price than expected, putting them in an unfavorable position.
function adjustPrice(uint256 newPrice) public onlyOwner noChallenge { if (newPrice > price) { restrictMinting(3 days); } else { checkCollateral(collateralBalance(), newPrice); } price = newPrice; emitUpdate(); }
When the position owner lowers the price, averting a challenge becomes easier. The challenger would be in an unfavorable position because their collateral can be sold at a lower price than they were expecting.
function tryAvertChallenge( uint256 _collateralAmount, uint256 _bidAmountZCHF ) external onlyHub returns (bool) { if (block.timestamp >= expiration) { return false; // position expired, let every challenge succeed } else if (_bidAmountZCHF * ONE_DEC18 >= price * _collateralAmount) {
if ( challenge.position.tryAvertChallenge(challenge.size, _bidAmountZCHF) ) { // bid was high enough, let bidder buy collateral from challenger zchf.transferFrom(msg.sender, challenge.challenger, _bidAmountZCHF); challenge.position.collateral().transfer( msg.sender, challenge.size );
Manual Review
* @param expectedSize size verification to guard against frontrunners doing a split-challenge-attack
Like in bid() function, consider adding a price verification parameter.
#0 - c4-pre-sort
2023-04-21T11:53:46Z
0xA5DF marked the issue as primary issue
#1 - c4-pre-sort
2023-04-21T11:56:54Z
0xA5DF marked the issue as duplicate of #945
#2 - c4-judge
2023-05-18T14:50:14Z
hansfriese marked the issue as satisfactory
#3 - c4-judge
2023-05-18T17:02:52Z
hansfriese changed the severity to 3 (High Risk)
🌟 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
/** * Adjust this position's limit to give away half of the remaining limit to the clone. * Invariant: global limit stays the same.
The function comment states that the function should adjust the position's limit to give away half of the remaining limit to the clone. However, the current implementation does not reflect this behavior:
uint256 reduction = (limit - minted - _minimum) / 2; limit -= reduction + _minimum; return reduction + _minimum;
For example , Expected behavior based on the comment would be:
limit = 1000 minted = 100
remaining_limit = limit - minted = 1000 - 100 = 900 clone_limit = remaining_limit / 2 = 450
However, the current implementation returns a clone_limit of 500 instead of the expected 450.
Limit calculation is wrong and can be advantageous for the clone.
Manual Review
#0 - c4-pre-sort
2023-04-26T13:51:52Z
0xA5DF marked the issue as duplicate of #932
#1 - c4-judge
2023-05-18T14:16:04Z
hansfriese marked the issue as satisfactory
🌟 Selected for report: juancito
Also found by: 0xAgro, 0xNorman, 0xSmartContract, 0xStalin, 0xTheC0der, 0xWaitress, 0xhacksmithh, 0xnev, 3dgeville, 8olidity, Arz, Aymen0909, BGSecurity, BRONZEDISC, Bauchibred, Bauer, BenRai, ChainHunters, ChrisTina, CodeFoxInc, DedOhWale, DishWasher, EloiManuel, IceBear, Inspex, Jorgect, Kaysoft, LeoGold, LewisBroadhurst, Madalad, MiloTruck, MohammedRizwan, Nyx, Polaris_tow, RaymondFam, SaharDevep, SanketKogekar, Sathish9098, SolidityATL, Udsen, W0RR1O, aria, ayden, berlin-101, bin2chen, catellatech, codeslide, crc32, decade, descharre, evmboi32, eyexploit, fatherOfBlocks, georgits, giovannidisiena, joestakey, karanctf, kodyvim, ltyu, lukris02, m9800, matrix_0wl, mov, mrpathfindr, nadin, niser93, p0wd3r, parlayan_yildizlar_takimi, pavankv, pontifex, qpzm, ravikiranweb3, rbserver, santipu_, shealtielanz, slvDev, tnevler, wonjun, xmxanuel, yixxas
22.6007 USDC - $22.60
Low - 1 - Centralization Issue
function deny(address[] calldata helpers, string calldata message) public { if (block.timestamp >= start) revert TooLate(); IReserve(zchf.reserve()).checkQualified(msg.sender, helpers); cooldown = expiration; // since expiration is immutable, we put it under cooldown until the end emit PositionDenied(msg.sender, message); }
Shareholders can prevent opening any position they want.
Low - 2 - burn() function doesnt check horizon
function mintInternal(address target, uint256 amount) internal { require(block.timestamp <= horizon, "expired"); require(chf.balanceOf(address(this)) <= limit, "limit"); zchf.mint(target, amount); }
The mint() function includes a check to determine whether the bridge is expired or not, but the burn() function does not have a similar check in place.
#0 - c4-pre-sort
2023-04-26T16:56:39Z
0xA5DF marked the issue as low quality report
#1 - 0xA5DF
2023-04-26T16:56:58Z
#1 is by design #2 - not clear why there should be such a check
#2 - c4-judge
2023-05-16T03:18:09Z
hansfriese marked the issue as grade-c
#3 - c4-judge
2023-05-18T07:51:13Z
hansfriese marked the issue as grade-b