Platform: Code4rena
Start Date: 25/10/2022
Pot Size: $50,000 USDC
Total HM: 18
Participants: 127
Period: 5 days
Judge: 0xean
Total Solo HM: 9
Id: 175
League: ETH
Rank: 72/127
Findings: 1
Award: $36.73
š Selected for report: 0
š Solo Findings: 0
š Selected for report: 0x1f8b
Also found by: 0xNazgul, 0xSmartContract, Aymen0909, B2, Bnke0x0, Deivitto, Diana, Dinesh11G, ElKu, JC, Josiah, Rahoz, RaymondFam, ReyAdmirado, Rolezn, Waze, __141345__, adriro, aphak5010, brgltd, c3phas, c7e7eff, carlitox477, cducrest, ch0bu, chrisdior4, cryptonue, cryptostellar5, cylzxje, d3e4, delfin454000, enckrish, evmwanderer, fatherOfBlocks, gogo, hansfriese, horsefacts, immeas, leosathya, lukris02, neumo, oyc_109, pedr02b2, rbserver, robee, rotcivegaf, rvierdiiev, sakshamguruji, shark, simon135, tnevler, trustindistrust, wagmi
36.7345 USDC - $36.73
L-N | Issue | Instances |
---|---|---|
[Lā01] | Open TODO | 1 |
N-N | Issue | Instances |
---|---|---|
[Nā01] | Require without custom errors | 3 |
[Nā02] | Non-library/interface files should use fixed compiler versions, not floating ones | 8 |
[Nā03] | Each interface should be declared in separate files | 13 |
[Nā04] | Lint | |
[Nā05] | Constants should be defined and documented rather than using magic numbers | 25 |
[Nā06] | Wrong order in contracts | 8 |
[Nā07] | Critical functions don't emit events | 25 |
Open TODO can point to architecture or programming issues that still need to be resolved.
File: src/escrows/INVEscrow.sol 35 xINV = _xINV; // TODO: Test whether an immutable variable will persist across proxies
Use custom errors to give the idea what was the cause of failure
File: src/escrows/GovTokenEscrow.sol 67 require(msg.sender == beneficiary);
File: src/escrows/INVEscrow.sol 91 require(msg.sender == beneficiary);
File: src/Fed.sol 93 require(globalSupply <= supplyCeiling);
File: src/BorrowController.sol 2 pragma solidity ^0.8.13;
File: src/DBR.sol 2 pragma solidity ^0.8.13;
File: src/Market.sol 2 pragma solidity ^0.8.13;
File: src/Oracle.sol 2 pragma solidity ^0.8.13;
File: src/Fed.sol 2 pragma solidity ^0.8.13;
File: src/escrows/SimpleERC20Escrow.sol 2 pragma solidity ^0.8.13;
File: src/escrows/INVEscrow.sol 2 pragma solidity ^0.8.13;
File: src/escrows/GovTokenEscrow.sol 2 pragma solidity ^0.8.13;
File: src/Market.sol 5 interface IERC20 { 6 function transfer(address,uint) external returns (bool); 7 function transferFrom(address,address,uint) external returns (bool); 8 function balanceOf(address) external view returns (uint); 9 } 11 interface IOracle { 12 function getPrice(address,uint) external returns (uint); 13 function viewPrice(address,uint) external view returns (uint); 14 } 16 interface IEscrow { 17 function initialize(IERC20 _token, address beneficiary) external; 18 function onDeposit() external; 19 function pay(address recipient, uint amount) external; 20 function balance() external view returns (uint); 21 } 23 interface IDolaBorrowingRights { 24 function onBorrow(address user, uint additionalDebt) external; 25 function onRepay(address user, uint repaidDebt) external; 26 function onForceReplenish(address user, uint amount) external; 27 function balanceOf(address user) external view returns (uint); 28 function deficitOf(address user) external view returns (uint); 29 function replenishmentPriceBps() external view returns (uint); 30 } 32 interface IBorrowController { 33 function borrowAllowed(address msgSender, address borrower, uint amount) external returns (bool); 34 }
File: src/Oracle.sol 4 interface IChainlinkFeed { 5 function decimals() external view returns (uint8); 6 function latestAnswer() external view returns (uint); 7 }
File: src/Fed.sol 4 interface IMarket { 5 function recall(uint amount) external; 6 function totalDebt() external view returns (uint); 7 function borrowPaused() external view returns (bool); 8 } 10 interface IDola { 11 function mint(address to, uint amount) external; 12 function burn(uint amount) external; 13 function balanceOf(address user) external view returns (uint); 14 function transfer(address to, uint amount) external returns (bool); 15 } 17 interface IDBR { 18 function markets(address) external view returns (bool); 19 }
File: src/escrows/SimpleERC20Escrow.sol 5 interface IERC20 { 6 function transfer(address,uint) external returns (bool); 7 function transferFrom(address,address,uint) external returns (bool); 8 function balanceOf(address) external view returns (uint); 9 }
File: src/escrows/INVEscrow.sol 5 interface IERC20 { 6 function transfer(address,uint) external returns (bool); 7 function transferFrom(address,address,uint) external returns (bool); 8 function balanceOf(address) external view returns (uint); 9 function approve(address, uint) external view returns (uint); 10 function delegate(address delegatee) external; 11 function delegates(address delegator) external view returns (address delegatee); 12 } 14 interface IXINV { 15 function balanceOf(address) external view returns (uint); 16 function exchangeRateStored() external view returns (uint); 17 function mint(uint mintAmount) external returns (uint); 18 function redeemUnderlying(uint redeemAmount) external returns (uint); 19 function syncDelegate(address user) external; 20 }
File: src/escrows/GovTokenEscrow.sol 5 interface IERC20 { 7 function transfer(address,uint) external returns (bool); 8 function transferFrom(address,address,uint) external returns (bool); 9 function balanceOf(address) external view returns (uint); 10 function delegate(address delegatee) external; 11 function delegates(address delegator) external view returns (address delegatee); 12 }
Remove space:
File: src/BorrowController.sol 9 \n
File: src/DBR.sol 10 \n
File: src/Market.sol 37 \n
File: src/Oracle.sol 17 \n 148 \n
File: src/Fed.sol 27 \n 139 \n 142 \n
File: src/Oracle.sol 87 uint8 decimals = 36 - feedDecimals - tokenDecimals; 95 uint newBorrowingPower = normalizedPrice * collateralFactorBps / 10000; 98 uint dampenedPrice = twoDayLow * 10000 / collateralFactorBps; 121 uint8 decimals = 36 - feedDecimals - tokenDecimals; 134 uint newBorrowingPower = normalizedPrice * collateralFactorBps / 10000; 137 uint dampenedPrice = twoDayLow * 10000 / collateralFactorBps;
File: src/Market.sol 74 require(_collateralFactorBps < 10000, "Invalid collateral factor"); 75 require(_liquidationIncentiveBps > 0 && _liquidationIncentiveBps < 10000, "Invalid liquidation incentive"); 76 require(_replenishmentIncentiveBps < 10000, "Replenishment incentive must be less than 100%"); 150 require(_collateralFactorBps < 10000, "Invalid collateral factor"); 162 require(_liquidationFactorBps > 0 && _liquidationFactorBps <= 10000, "Invalid liquidation factor"); 173 require(_replenishmentIncentiveBps > 0 && _replenishmentIncentiveBps < 10000, "Invalid replenishment incentive"); 184 require(_liquidationIncentiveBps > 0 && _liquidationIncentiveBps + liquidationFeeBps < 10000, "Invalid liquidation incentive"); 195 require(_liquidationFeeBps > 0 && _liquidationFeeBps + liquidationIncentiveBps < 10000, "Invalid liquidation fee"); 336 return collateralValue * collateralFactorBps / 10000; 346 return collateralValue * collateralFactorBps / 10000; 360 uint minimumCollateral = debt * 1 ether / oracle.getPrice(address(collateral), collateralFactorBps) * 10000 / collateralFactorBps; 377 uint minimumCollateral = debt * 1 ether / oracle.viewPrice(address(collateral), collateralFactorBps) * 10000 / collateralFactorBps; 563 uint replenishmentCost = amount * dbr.replenishmentPriceBps() / 10000; 564 uint replenisherReward = replenishmentCost * replenishmentIncentiveBps / 10000; 583 return debt * liquidationFactorBps / 10000; 595 require(repaidDebt <= debt * liquidationFactorBps / 10000, "Exceeded liquidation factor"); 598 liquidatorReward += liquidatorReward * liquidationIncentiveBps / 10000; 606 uint liquidationFee = repaidDebt * 1 ether / price * liquidationFeeBps / 10000;
File: DBR.sol 330 uint replenishmentCost = amount * replenishmentPriceBps / 10000;
The best-practice layout for a contract should follow the following order: state variables, events, modifiers, constructor and functions Suggestion: Consider reorder the events and modifiers
File: src/BorrowController.sol 17 modifier onlyOperator { 18 require(msg.sender == operator, "Only operator"); 19 _; 20 }
File: DBR.sol 44 modifier onlyOperator { 45 require(msg.sender == operator, "ONLY OPERATOR"); 46 _; 47 } 381 event Transfer(address indexed from, address indexed to, uint256 amount); 382 event Approval(address indexed owner, address indexed spender, uint256 amount); 383 event AddMinter(address indexed minter); 384 event RemoveMinter(address indexed minter); 385 event AddMarket(address indexed market); 386 event ChangeOperator(address indexed newOperator);
File: src/Market.sol 92 modifier onlyGov { 93 require(msg.sender == gov, "Only gov can call this function"); 94 _; 95 } 614 event Deposit(address indexed account, uint amount); 615 event Borrow(address indexed account, uint amount); 616 event Withdraw(address indexed account, address indexed to, uint amount); 617 event Repay(address indexed account, address indexed repayer, uint amount); 618 event ForceReplenish(address indexed account, address indexed replenisher, uint deficit, uint replenishmentCost, uint replenisherReward); 619 event Liquidate(address indexed account, address indexed liquidator, uint repaidDebt, uint liquidatorReward); 620 event CreateEscrow(address indexed user, address escrow);
File: src/Oracle.sol 35 modifier onlyOperator { 37 require(msg.sender == operator, "ONLY OPERATOR"); 38 _; 39 } 146 event ChangeOperator(address indexed newOperator); 147 event RecordDailyLow(address indexed token, uint price);
File: src/Fed.sol 140 event Expansion(IMarket indexed market, uint amount); 141 event Contraction(IMarket indexed market, uint amount);
Each function that changes the state of the contract should have an associated event to facilitate off-chain monitoring
File: src/BorrowController.sol 26 function setOperator(address _operator) public onlyOperator { operator = _operator; } 32 function allow(address allowedContract) public onlyOperator { contractAllowlist[allowedContract] = true; } 38 function deny(address deniedContract) public onlyOperator { contractAllowlist[deniedContract] = false; }
File: src/DBR.sol 53 function setPendingperator(address newOperator_) public onlyOperator { 62 function setReplenishmentPriceBps(uint newReplenishmentPriceBps_) public onlyOperator { 259 function invalidateNonce() public {
File: src/Market.sol 118 function setOracle(IOracle _oracle) public onlyGov { oracle = _oracle; } 124 function setBorrowController(IBorrowController _borrowController) public onlyGov { borrowController = _borrowController; } 130 function setGov(address _gov) public onlyGov { gov = _gov; } 136 function setLender(address _lender) public onlyGov { lender = _lender; } 142 function setPauseGuardian(address _pauseGuardian) public onlyGov { pauseGuardian = _pauseGuardian; } 149 function setCollateralFactorBps(uint _collateralFactorBps) public onlyGov { 161 function setLiquidationFactorBps(uint _liquidationFactorBps) public onlyGov { 172 function setReplenismentIncentiveBps(uint _replenishmentIncentiveBps) public onlyGov { 183 function setLiquidationIncentiveBps(uint _liquidationIncentiveBps) public onlyGov { 194 function setLiquidationFeeBps(uint _liquidationFeeBps) public onlyGov { 212 function pauseBorrows(bool _value) public { 520 function invalidateNonce() public {
File: src/Oracle.sol 44 function setPendingOperator(address newOperator_) public onlyOperator { pendingOperator = newOperator_; } 53 function setFeed(address token, IChainlinkFeed feed, uint8 tokenDecimals) public onlyOperator { feeds[token] = FeedData(feed, tokenDecimals); } 61 function setFixedPrice(address token, uint price) public onlyOperator { fixedPrices[token] = price; }
File: src/Fed.sol 48 function changeGov(address _gov) public { 57 function changeSupplyCeiling(uint _supplyCeiling) public { 66 function changeChair(address _chair) public { 75 function resign() public {
#0 - c4-judge
2022-11-08T00:31:43Z
0xean marked the issue as grade-b