Constants should be defined rather than using magic numbers
There are several occurrences of literal values with unexplained meaning .Literal values in the codebase without an explained meaning make the code harder to read, understand and maintain, thus hindering the experience of developers, auditors and external contributors alike.
Developers should define a constant variable for every magic value used , giving it a clear and self-explanatory name.
Public functions not called by the contract should be declared external instead
Contracts are allowed to override their parents' functions and change the visibility from external to public.
Functions marked by external use call data to read arguments, where public will first allocate in local memory and then load them.
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 {
267: function depositAndBorrow(uint amountDeposit, uint amountBorrow) public {
370: function getWithdrawalLimit(address user) public view returns (uint) {
422: function borrowOnBehalf(address from, uint amount, uint deadline, uint8 v, bytes32 r, bytes32 s) public {
486: function withdrawOnBehalf(address from, uint amount, uint deadline, uint8 v, bytes32 r, bytes32 s) public {
520: function invalidateNonce() public {
546: function repayAndWithdraw(uint repayAmount, uint withdrawAmount) public {
578: function getLiquidatableDebt(address user) public view returns (uint) {
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 {
86: function expansion(IMarket market, uint amount) public {
103: function contraction(IMarket market, uint amount) public {
131: function takeProfit(IMarket market) public {
File: /src/DBR.sol
53: function setPendingOperator(address newOperator_) public onlyOperator {
62: function setReplenishmentPriceBps(uint newReplenishmentPriceBps_) public onlyOperator {
File: /src/Fed.sol
48: function changeGov(address _gov) public {
57: function changeSupplyCeiling(uint _supplyCeiling) public {
66: function changeChair(address _chair) public {
Inconsistency in using uint vs uint256
uint is simply an alias for uint256 . Throughout the code , the use of uint seems to be the preference.
File: /src/Market.sol
58: mapping (address => uint) public debts; // user => debt
59: mapping(address => uint256) public nonces; // user => nonce
Since majority of the code is utilizing uint we should utilize this in all the codebase for consistency
Code Structure Deviates From Best-Practice
The best-practice layout for a contract should follow the following order: state variables, events, modifiers, constructor and functions. Function ordering helps readers identify which functions they can call and find constructor and fallback functions easier. Functions should be grouped according to their visibility and ordered as: constructor, receive function (if exists), fallback function (if exists), external, public, internal, private. Some constructs deviate from this recommended best-practice: Modifiers are in the middle of contracts. External/public functions are mixed with internal/private ones.
QA
Missing checks for address(0x0) when assigning values to address state variables
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Market.sol#L77-L80
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Oracle.sol#L32
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Fed.sol#L39-L40
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/BorrowController.sol#L14
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/DBR.sol#L39
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/escrows/GovTokenEscrow.sol#L34
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/escrows/INVEscrow.sol#L48
Constants should be defined rather than using magic numbers
There are several occurrences of literal values with unexplained meaning .Literal values in the codebase without an explained meaning make the code harder to read, understand and maintain, thus hindering the experience of developers, auditors and external contributors alike.
Developers should define a constant variable for every magic value used , giving it a clear and self-explanatory name.
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Market.sol#L74
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Oracle.sol#L87
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/DBR.sol#L122
Public functions not called by the contract should be declared external instead
Contracts are allowed to override their parents' functions and change the visibility from external to public. Functions marked by external use call data to read arguments, where public will first allocate in local memory and then load them.
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Market.sol#L118
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Oracle.sol#L44
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Fed.sol#L48
Open todos
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/escrows/INVEscrow.sol#L35
Missing friendly revert strings
require()/revert() statements should have descriptive reason strings.
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Fed.sol#L93
Missing event for critical initialize function
Events help non-contract tools to track changes, and events prevent users from being surprised by changes.
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/escrows/GovTokenEscrow.sol#L30-L36
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/escrows/INVEscrow.sol#L44-L52
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/escrows/SimpleERC20Escrow.sol#L25-L29
Missing events for setters
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Market.sol#L118
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Oracle.sol#L44
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/BorrowController.sol#L26
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/DBR.sol#L53
Lack of event emission after critical functions
https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Fed.sol#L48
Inconsistency in using uint vs uint256
uint
is simply an alias foruint256
. Throughout the code , the use ofuint
seems to be the preference.https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Market.sol#L58-L59
Since majority of the code is utilizing
uint
we should utilize this in all the codebase for consistencyCode Structure Deviates From Best-Practice
The best-practice layout for a contract should follow the following order: state variables, events, modifiers, constructor and functions. Function ordering helps readers identify which functions they can call and find constructor and fallback functions easier. Functions should be grouped according to their visibility and ordered as: constructor, receive function (if exists), fallback function (if exists), external, public, internal, private. Some constructs deviate from this recommended best-practice: Modifiers are in the middle of contracts. External/public functions are mixed with internal/private ones.
In the following, events are declared at the end of the file. https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Market.sol#L614-L620 https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Oracle.sol#L146-L147 https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Fed.sol#L140-L141 https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/DBR.sol#L381-L386
We have internal functions coming before public ones https://github.com/code-423n4/2022-10-inverse/blob/3e81f0f5908ea99b36e6ab72f13488bbfe622183/src/Market.sol#L460
Recommendation: Consider adopting recommended best-practice for code structure and layout.
See: https://docs.soliditylang.org/en/v0.8.15/style-guide.html#order-of-layout