Platform: Code4rena
Start Date: 03/07/2023
Pot Size: $40,000 USDC
Total HM: 14
Participants: 74
Period: 7 days
Judge: alcueca
Total Solo HM: 9
Id: 259
League: ETH
Rank: 13/74
Findings: 2
Award: $303.89
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: SM3_SS
Also found by: 0x11singh99, 0xAnah, 0xSmartContract, 0xn006e7, 0xprinc, DavidGiladi, ElCid, JCN, K42, MIQUINHO, Raihan, Rolezn, SAAJ, SY_S, Strausses, TheSavageTeddy, bigtone, erebus, hunter_w3b, josephdara, lsaudit, mahdirostami, oakcobalt, peanuts, pfapostol, seth_lawson
7.8853 USDC - $7.89
Due to how constant variables are implemented (replacements at compile-time), an expression assigned to a constant variable is recomputed each time that the variable is used, which wastes some gas.
** ~200 gas saved and deploy gas saved: ~22k **
src\Well.sol: 29: bytes32 constant RESERVES_STORAGE_SLOT = bytes32(uint256(keccak256("reserves.storage.slot")) - 1);
src\Well.sol: - 29: bytes32 constant RESERVES_STORAGE_SLOT = bytes32(uint256(keccak256("reserves.storage.slot")) - 1); + 29: bytes32 constant RESERVES_STORAGE_SLOT = 0x4bba01c388049b5ebd30398b65e8ad45b632802c5faf4964e58085ea8ab03715;
https://github.com/code-423n4/2023-07-basin/blob/main/src/Well.sol#L29
** deploy gas saved: ~55k **
src\Well.sol: 26: uint256 constant ONE_WORD = 32; 27: uint256 constant PACKED_ADDRESS = 20; 28: uint256 constant ONE_WORD_PLUS_PACKED_ADDRESS = 52; // For gas efficiency purposes 55: /// TYPE NAME LOCATION (CONSTANT) 77: uint256 constant LOC_AQUIFER_ADDR = 0; 78: uint256 constant LOC_TOKENS_COUNT = LOC_AQUIFER_ADDR + PACKED_ADDRESS; 79: uint256 constant LOC_WELL_FUNCTION_ADDR = LOC_TOKENS_COUNT + ONE_WORD; 80: uint256 constant LOC_WELL_FUNCTION_DATA_LENGTH = LOC_WELL_FUNCTION_ADDR + PACKED_ADDRESS; 81: uint256 constant LOC_PUMPS_COUNT = LOC_WELL_FUNCTION_DATA_LENGTH + ONE_WORD; 82: uint256 constant LOC_VARIABLE = LOC_PUMPS_COUNT + ONE_WORD;
src\Well.sol: 26: uint256 constant ONE_WORD = 32; 27: uint256 constant PACKED_ADDRESS = 20; 28: uint256 constant ONE_WORD_PLUS_PACKED_ADDRESS = 52; // For gas efficiency purposes 77: uint256 constant LOC_AQUIFER_ADDR = 0; - 78: uint256 constant LOC_TOKENS_COUNT = LOC_AQUIFER_ADDR + PACKED_ADDRESS; // LOC_TOKENS_COUNT = LOC_AQUIFER_ADDR + PACKED_ADDRESS = 0 + 20 + 78: uint256 constant LOC_TOKENS_COUNT = 20; (~190 gas saved) - 79: uint256 constant LOC_WELL_FUNCTION_ADDR = LOC_TOKENS_COUNT + ONE_WORD; // LOC_WELL_FUNCTION_ADDR = LOC_TOKENS_COUNT + ONE_WORD = 20 + 32 + 79: uint256 constant LOC_WELL_FUNCTION_ADDR = 52; (~375 gas saved) - 80: uint256 constant LOC_WELL_FUNCTION_DATA_LENGTH = LOC_WELL_FUNCTION_ADDR + PACKED_ADDRESS; // LOC_WELL_FUNCTION_DATA_LENGTH = LOC_WELL_FUNCTION_ADDR + PACKED_ADDRESS = 52 + 20 + 80: uint256 constant LOC_WELL_FUNCTION_DATA_LENGTH = 72; (~560 gas saved) - 81: uint256 constant LOC_PUMPS_COUNT = LOC_WELL_FUNCTION_DATA_LENGTH + ONE_WORD; // LOC_PUMPS_COUNT = LOC_WELL_FUNCTION_DATA_LENGTH + ONE_WORD = 72 + 32 + 81: uint256 constant LOC_PUMPS_COUNT = 104; (~750 gas saved) - 82: uint256 constant LOC_VARIABLE = LOC_PUMPS_COUNT + ONE_WORD; // LOC_VARIABLE = LOC_PUMPS_COUNT + ONE_WORD = 104 + 32 + 82: uint256 constant LOC_VARIABLE = 136; (~940 gas saved)
https://github.com/code-423n4/2023-07-basin/blob/main/src/Well.sol#L78-L82
abi.encodeWithSelector is much cheaper than abi.encodeWithSignature because it doesn't require to compute the selector from the string.
Reference:
https://docs.soliditylang.org/en/v0.8.15/units-and-global-variables.html#abi-encoding-and-decoding-functions https://github.com/ConnorBlockchain/Solidity-Encode-Gas-Comparison
src\libraries\LibContractInfo.sol: 17: (bool success, bytes memory data) = _contract.staticcall(abi.encodeWithSignature("symbol()")); 35: (bool success, bytes memory data) = _contract.staticcall(abi.encodeWithSignature("name()")); 53: (bool success, bytes memory data) = _contract.staticcall(abi.encodeWithSignature("decimals()"));
https://github.com/code-423n4/2023-07-basin/blob/main/src/libraries/LibContractInfo.sol#L17 https://github.com/code-423n4/2023-07-basin/blob/main/src/libraries/LibContractInfo.sol#L35 https://github.com/code-423n4/2023-07-basin/blob/main/src/libraries/LibContractInfo.sol#L53
src\libraries\LibWellConstructor.sol: 81: initFunctionCall = abi.encodeWithSignature("init(string,string)", name, symbol);
https://github.com/code-423n4/2023-07-basin/blob/main/src/libraries/LibWellConstructor.sol#L81
The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the contract is meant to be extended, the contract should be abstract and the function signatures be added without any default implementation. If the block is an empty if-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if(x){}else if(y){...}else{...} => if(!x){if(y){...}else{...}}). Empty receive()/fallback() payable functions that are not used, can be removed to save deployment gas.
src\Aquifer.sol: 27: constructor() ReentrancyGuard() {}
https://github.com/code-423n4/2023-07-basin/blob/main/src/Aquifer.sol#L27
src\Well.sol: 114: function wellData() public pure returns (bytes memory) {}
https://github.com/code-423n4/2023-07-basin/blob/main/src/Well.sol#L114
#0 - c4-pre-sort
2023-07-12T08:05:43Z
141345 marked the issue as low quality report
#1 - c4-judge
2023-08-05T11:26:15Z
alcueca marked the issue as grade-b
296.0006 USDC - $296.00
List | Head | Details |
---|---|---|
a) | The approach I followed when reviewing the code | Stages in my code review and analysis |
b) | Analysis of the code base | What is unique? How are the existing patterns used? |
c) | Test analysis | Test scope of the project and quality of tests |
d) | Documents | What is the scope and quality of documentation for Users and Administrators? |
e) | Centralization risks | How was the risk of centralization handled in the project, what could be alternatives? |
f) | Security Approach of the Project | Audit approach of the Project |
g) | Other Audit Reports and Automated Findings | What are the previous Audit reports and their analysis |
h) | Gas Optimization | Gas usage approach of the project and alternative solutions to it |
i) | Project team | Details about the project team and approach |
j) | Other recommendations | What is unique? How are the existing patterns used? |
k) | New insights and learning from this audit | Things learned from the project |
First, by examining the scope of the code, I determined my code review and analysis strategy. https://github.com/code-423n4/2023-07-basin#scope
Accordingly, I analyzed and audited the subject in the following steps;
Number | Stage | Details | Information |
---|---|---|---|
1 | Compile and Run Test | Installation | Test and installation structure is simple, cleanly designed |
2 | Architecture Review | The Diagram explainer provides a high-level overview of the Project system | |
3 | Graphical Analysis | Graphical Analysis with Solidity-metrics | A visual view has been made to dominate the general structure of the codes of the project. |
4 | Slither Analysis | Slither Report | The Slither output did not indicate a direct security risk to us, but at some points it did give some insight into the project's careful scrutiny. |
5 | Test Suits | Tests | In this section, the scope and content of the tests of the project are analyzed. |
6 | Manuel Code Review | Scope | All codes are examined one by one from top to bottom |
7 | Project Audit Reports | Cyfrin Audit Report Halborn Audit Report | This reports gives us a clue about the topics that should be considered in the current audit |
8 | Infographic | Figma | I made Visual drawings to understand the hard-to-understand mechanisms |
9 | Special focus on Areas of Concern | Areas of Concern | The specific focus areas indicated by the project team are the most sensitive and the potential logic-mathematical errors are also focused on. |
Well.sol contract is the most important contract of the project, so most of the audit was on this contract. The code uses a dynamic immutable storage layout. This allows the contract to be gas-efficient when performing reads. The code uses a number of Solidity libraries to improve security and efficiency. The code has NatSpec which makes it easy to understand. Overall, the code is well-written and easy to understand. It implements a number of important features, such as a constant function AMM and a number of functions for swapping tokens between each other.
This contract implements a pump that stores a geometric EMA and cumulative geometric SMA for each reserve. The pump is designed for use in Beanstalk with 2 tokens. Multi-block MEV resistance reserves: The contract uses a geometric EMA to calculate the instantaneous reserve, which is resistant to MEV attacks. MEV-resistant geometric EMA: The contract uses a geometric EMA to calculate the instantaneous reserve, which is resistant to MEV attacks. MEV-resistant cumulative geometric: The contract uses a cumulative geometric SMA to calculate the SMA reserve, which is resistant to MEV attacks.
Test Coverage is 95% and 100% is best practice, tests are mainly unit tests, more integration tests should be added.
Documents can be increased, especially the increase in the documentation of mathematical models makes the audit easier and explains what is to be done technically better. https://basin.exchange/basin.pdf https://basin.exchange/multi-flow-pump.pdf
No centrality risk
Successful current security understanding of the project; 1 - First they did the main audit from a reputable auditing organizations like Halborn and Cyfrin and resolved all the security concerns in the report 2- They manage the 2nd audit process with an innovative audit such as Code4rena, in which many auditors examine the codes.
What the project should add in the understanding of Security; 1- By distributing the project to testnets, ensuring that the audits are carried out in onchain audit. (This will increase coverage) 2- After the project is published on the mainnet, there should be emergency action plans (not found in the documents)
Automated Findings: There are many incorrect notifications in Automatic Finding, it also shows the NounsDao project in the links, this part is completely invalid and has not been taken into account. https://gist.github.com/CloudEllie/53be96a57d19e7442313cad2a12ec11a
Other Audit Reports : Cryfin ve Halborn https://basin.exchange/cyfrin-basin-audit.pdf https://basin.exchange/halborn-basin-audit.pdf
Cryfin and Halborn audit reports are quality reports that have been examined in detail. There are good observations about Read Only Re-Entrancy and Mev, the project team has corrected them.
The project is generally gas-optimized and inline-assembly is reasonable in terms of readability and auditability.
In particular, the architecture in the Well contract is gas optimized. //////////////////// WELL DEFINITION ////////////////////
/// This Well uses a dynamic immutable storage layout. Immutable storage is /// used for gas-efficient reads during Well operation. The Well must be /// created by cloning with a pre-encoded byte string containing immutable /// data. /// /// Let n = number of tokens /// m = length of well function data (bytes) /// /// TYPE NAME LOCATION (CONSTANT) /// ============================================================== /// address aquifer() 0 (LOC_AQUIFER_ADDR) /// uint256 numberOfTokens() 20 (LOC_TOKENS_COUNT) /// address wellFunctionAddress() 52 (LOC_WELL_FUNCTION_ADDR) /// uint256 wellFunctionDataLength() 72 (LOC_WELL_FUNCTION_DATA_LENGTH) /// uint256 numberOfPumps() 104 (LOC_PUMPS_COUNT) /// -------------------------------------------------------------- /// address token0 136 (LOC_VARIABLE) /// ... /// address tokenN 136 + (n-1) * 32 /// -------------------------------------------------------------- /// byte wellFunctionData0 136 + n * 32 /// ... /// byte wellFunctionDataM 136 + n * 32 + m /// -------------------------------------------------------------- /// address pump1Address 136 + n * 32 + m /// uint256 pump1DataLength 136 + n * 32 + m + 20 /// byte pump1Data 136 + n * 32 + m + 52 /// ... /// ==============================================================
Information not available
Logic similar to singleton pattern similar to Uniswapv4 can be used in a project, this is a gas-optimized and innovative solution
-As it is known with Uniswapv4, hook features tend to liberate MEV and this is aimed at eliminating the formability deficiency, the future is in these projects, the Basin project is based on eliminating the formability deficiency, in this context, what I learned most from this project is how this formability architecture can be. -Multi-block MEV resistance reserves , MEV-resistant geometric EMA, I gained considerable knowledge in MEV-resistant cumulative geometric designs
8 hours
#0 - c4-pre-sort
2023-07-12T12:00:36Z
141345 marked the issue as high quality report
#1 - c4-sponsor
2023-08-03T21:07:57Z
publiuss marked the issue as sponsor acknowledged
#2 - c4-judge
2023-08-05T20:17:13Z
alcueca marked the issue as grade-a