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: 69/127
Findings: 2
Award: $55.74
🌟 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
All important functions wherever some change is happening need to raise events
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol
53: function setPendingOperator(address newOperator_) public onlyOperator { 62: function setReplenishmentPriceBps(uint newReplenishmentPriceBps_) public onlyOperator {
In the contracts, floating pragmas should not be used. Contracts should be deployed with the same compiler version and flags that they have been tested with thoroughly. Locking the pragma helps to ensure that contracts do not accidentally get deployed using, for example, an outdated compiler version that might introduce bugs that affect the contract system negatively.
This is applicable in all the smart contracts
pragma solidity ^0.8.13;
Most of the other interfaces in this project are in their own file in the interfaces directory. The interfaces below do not follow this pattern
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Fed.sol
interface IMarket { function recall(uint amount) external; function totalDebt() external view returns (uint); function borrowPaused() external view returns (bool); } interface IDola { function mint(address to, uint amount) external; function burn(uint amount) external; function balanceOf(address user) external view returns (uint); function transfer(address to, uint amount) external returns (bool); } interface IDBR { function markets(address) external view returns (bool); }
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol
interface IERC20 { function transfer(address,uint) external returns (bool); function transferFrom(address,address,uint) external returns (bool); function balanceOf(address) external view returns (uint); } interface IOracle { function getPrice(address,uint) external returns (uint); function viewPrice(address,uint) external view returns (uint); } interface IEscrow { function initialize(IERC20 _token, address beneficiary) external; function onDeposit() external; function pay(address recipient, uint amount) external; function balance() external view returns (uint); } interface IDolaBorrowingRights { function onBorrow(address user, uint additionalDebt) external; function onRepay(address user, uint repaidDebt) external; function onForceReplenish(address user, uint amount) external; function balanceOf(address user) external view returns (uint); function deficitOf(address user) external view returns (uint); function replenishmentPriceBps() external view returns (uint); } interface IBorrowController { function borrowAllowed(address msgSender, address borrower, uint amount) external returns (bool); }
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Oracle.sol
interface IChainlinkFeed { function decimals() external view returns (uint8); function latestAnswer() external view returns (uint); }
https://github.com/code-423n4/2022-10-inverse/blob/main/src/escrows/GovTokenEscrow.sol
interface IERC20 { function transfer(address,uint) external returns (bool); function transferFrom(address,address,uint) external returns (bool); function balanceOf(address) external view returns (uint); function delegate(address delegatee) external; function delegates(address delegator) external view returns (address delegatee); }
https://github.com/code-423n4/2022-10-inverse/blob/main/src/escrows/INVEscrow.sol
interface IERC20 { function transfer(address,uint) external returns (bool); function transferFrom(address,address,uint) external returns (bool); function balanceOf(address) external view returns (uint); function approve(address, uint) external view returns (uint); function delegate(address delegatee) external; function delegates(address delegator) external view returns (address delegatee); } interface IXINV { function balanceOf(address) external view returns (uint); function exchangeRateStored() external view returns (uint); function mint(uint mintAmount) external returns (uint); function redeemUnderlying(uint redeemAmount) external returns (uint); function syncDelegate(address user) external; }
https://github.com/code-423n4/2022-10-inverse/blob/main/src/escrows/SimpleERC20Escrow.sol
interface IERC20 { function transfer(address,uint) external returns (bool); function transferFrom(address,address,uint) external returns (bool); function balanceOf(address) external view returns (uint); }
Each event
 should use three indexed
 fields if there are three or more fields
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol
381: event Transfer(address indexed from, address indexed to, uint256 amount); 382: event Approval(address indexed owner, address indexed spender, uint256 amount);
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Fed.sol
140: event Expansion(IMarket indexed market, uint amount); 141: event Contraction(IMarket indexed market, uint amount);
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol
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);
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Oracle.sol
147: event RecordDailyLow(address indexed token, uint price);
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Fed.sol
93: require(globalSupply <= supplyCeiling);
https://github.com/code-423n4/2022-10-inverse/blob/main/src/escrows/GovTokenEscrow.sol
67: require(msg.sender == beneficiary);
https://github.com/code-423n4/2022-10-inverse/blob/main/src/escrows/INVEscrow.sol
91: require(msg.sender == beneficiary);
https://github.com/code-423n4/2022-10-inverse/blob/main/src/escrows/INVEscrow.sol
35: Â xINV = _xINV; // TODO: Test whether an immutable variable will persist across proxies
This is applicable throughout the contracts. 1 such instance is:
16: contract SimpleERC20Escrow { // missing @params
"th" is a typo instead of "the"
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol
128: @notice Get the DBR deficit of an address. Will return 0 if th user has zero DBR or more.
#0 - c4-judge
2022-11-07T21:26:24Z
0xean marked the issue as grade-b
🌟 Selected for report: pfapostol
Also found by: 0x1f8b, 0xRoxas, 0xSmartContract, Amithuddar, Aymen0909, B2, Bnke0x0, Chandr, CloudX, Deivitto, Diana, Dinesh11G, ElKu, HardlyCodeMan, JC, JrNet, KoKo, Mathieu, Ozy42, Rahoz, RaymondFam, ReyAdmirado, Rolezn, Shinchan, __141345__, adriro, ajtra, aphak5010, ballx, c3phas, carlitox477, ch0bu, chaduke, cryptostellar5, djxploit, durianSausage, enckrish, exolorkistis, fatherOfBlocks, gogo, horsefacts, kaden, karanctf, leosathya, martin, mcwildy, oyc_109, ret2basic, robee, sakman, sakshamguruji, shark, skyle, tnevler
19.0072 USDC - $19.01
Number of Instances Identified: 8
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol
249: require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol
75: require(_liquidationIncentiveBps > 0 && _liquidationIncentiveBps < 10000, "Invalid liquidation incentive"); 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"); 448: require(recoveredAddress != address(0) && recoveredAddress == from, "INVALID_SIGNER"); 512: require(recoveredAddress != address(0) && recoveredAddress == from, "INVALID_SIGNER");
Number of Instances Identified: 1
if (<x> == true)
 => if (<x>)
, if (<x> == false)
 => if (!<x>)
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol
350: require(minters[msg.sender] == true || msg.sender == operator, "ONLY MINTERS OR OPERATOR");
Number of Instances Identified: 4
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol
63: require(newReplenishmentPriceBps_ > 0, "replenishment price must be over 0"); 326: require(markets[msg.sender], "Only markets can call onForceReplenish");
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol
75: require(_liquidationIncentiveBps > 0 && _liquidationIncentiveBps < 10000, "Invalid liquidation incentive"); 214: require(msg.sender == pauseGuardian || msg.sender == gov, "Only pause guardian or governance can pause");
Number of Instances Identified: 6
Saves deployment costs
The following require and revert checks have been used more than once within the same contract, hence they should be refactored to a modifier or a function
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol
195: require(balanceOf(from) >= amount, "Insufficient balance"); 314: require(markets[msg.sender], "Only markets can call onRepay");
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Fed.sol
48: require(msg.sender == gov, "ONLY GOV"); 76: require(msg.sender == chair, "ONLY CHAIR");
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Oracle.sol
104: revert("Price not found"); 117: require(price > 0, "Invalid feed price");
Number of Instances Identified: 6
When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.
https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Use a larger size then downcast where needed
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Oracle.sol
85: uint8 feedDecimals = feeds[token].feed.decimals(); 86: uint8 tokenDecimals = feeds[token].tokenDecimals; 87: uint8 decimals = 36 - feedDecimals - tokenDecimals; 119: uint8 feedDecimals = feeds[token].feed.decimals(); 120: uint8 tokenDecimals = feeds[token].tokenDecimals; 121: uint8 decimals = 36 - feedDecimals - tokenDecimals;
Number of Instances Identified: 26
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol
172: balances[msg.sender] -= amount; 174: balances[to] += amount; 196: balances[from] -= amount; 198: balances[to] += amount; 288: dueTokensAccrued[user] += accrued; 289: totalDueTokensAccrued += accrued; 304: debts[user] += additionalDebt; 316: debts[user] -= repaidDebt; 332: debts[user] += replenishmentCost; 360: _totalSupply += amount; 362: balances[to] += amount; 374: balances[from] -= amount; 376: Â _totalSupply -= amount;
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Fed.sol
91: supplies[market] += amount; 92: globalSupply += amount; 110: supplies[market] -= amount; 111: globalSupply -= amount;
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol
395: debts[borrower] += amount; 397: totalDebt += amount; 534: debts[user] -= amount; 535: totalDebt -= amount; 565: debts[user] += replenishmentCost; 568: totalDebt += replenishmentCost; 598: liquidatorReward += liquidatorReward * liquidationIncentiveBps / 10000; 599: debts[user] -= repaidDebt; 600: totalDebt -= repaidDebt;
Number of Instances Identified: 6
// Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled.
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/58f635312aa21f947cae5f8578638a85aa2519f5/contracts/security/ReentrancyGuard.sol#L23-L27 Use uint256(1)
 and uint256(2)
 for true/false to avoid a Gwarmaccess (100 gas) for the extra SLOAD, and to avoid Gsset (20000 gas) when changing from ‘false’ to ‘true’, after having been ‘true’ in the past
https://github.com/code-423n4/2022-10-inverse/blob/main/src/BorrowController.sol
11: mapping(address => bool) public contractAllowlist;
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol
24: mapping (address => bool) public minters; 25: mapping (address => bool) public markets;
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol
52: bool immutable callOnDepositCallback; 53: bool public borrowPaused; 72: bool _callOnDepositCallback
Number of Instances Identified: 66
Some of them include : https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol
45: require(msg.sender == operator, "ONLY OPERATOR"); 63: require(newReplenishmentPriceBps_ > 0, "replenishment price must be over 0"); 224: require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
Number of Instances Identified: 5
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol
239: nonces[owner]++ 259: nonces[msg.sender]++;
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol
438: nonces[from]++ 502: nonces[from]++, 521: nonces[msg.sender]++;
> 0
 COSTS MORE GAS THAN != 0
 WHEN USED ON A UINT
 Number of Instances Identified: 20
some of them include :
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol
63: require(newReplenishmentPriceBps_ > 0, "replenishment price must be over 0"); 328: require(deficit > 0, "No deficit");
#0 - c4-judge
2022-11-05T23:41:11Z
0xean marked the issue as grade-b