-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial implementation #2
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left a few comments.
There's also another issue that doesn't show in the PR:
https://github.com/dewiz-xyz/rates-conv/blob/master/foundry.toml#L8-L9
Do we want optimizations enabled? If so, why are we optimizing for 1 run? Is it to save on contract deployment size vs runtime cost?
Would it be possible to NOT have this contract optimized? Or if it's optimized, maybe use a higher value for runs
?
Other than that, here's the reviewer checklist:
Code Review: 2025-02-17 rates-conv
Preparation and Context
- Understand Requirements
- Review related documentation, user stories, or issue tickets, and Technical Requirements Doc.
- Ensure a clear understanding of the contract's purpose and functionality.
- Assumptions and Constraints
- Verify that these assumptions hold true under all expected and edge case conditions. Check assumptions in the Technical Requirement Doc
Contract Design
- Ensure the contract is modular and logically organized.
- Verify proper separation of concerns and encapsulation.
✅ The contract provides a clear separation of concerns (only conversion of rates) and is well-organized. - Challenge the overall design and logic of the contract.
- Ensure that the design aligns with security best practices and minimizes attack surfaces.
Security Considerations
Reentrancy: Check for vulnerabilities, ensure use ofReentrancyGuard
if needed.
✅ N/A: the contract is immutable and read-only- Integer Overflow/Underflow: Ensure usage of SafeMath library or built-in overflow checks.
✅ Assembly code has the proper overflow checks
✅ Solidity code uses the default safe math from 0.8.x Access Control: Verify correct use of access control modifiers (e.g.,onlyOwner
).
✅ N/A: the contract is immutable and permissionlessFront-running: Assess susceptibility to front-running attacks and implement mitigation strategies.Randomness: Ensure secure generation of random numbers.Timestamp Dependence: Avoid reliance onblock.timestamp
for critical logic.External Calls: Minimize and carefully manageexternal
contract calls.Denial of Service: Prevent potential DoS attacks, especially inpayable
functions.- Further information https://swcregistry.io/, https://dacian.me/defi-slippage-attacks, https://www.rareskills.io/post/smart-contract-security, https://solodit.xyz/
General checks
- Visibility Specifiers: Ensure correct use of public, private, internal, and external.
⚠️ rtob
should beexternal
rather thanpublic
⚠️ btor
should beexternal
rather thanpublic
-
Modifiers: Review custom and built-in modifiers for security and correctness. - Pure and View: Use pure and view appropriately to save gas and convey intent.
-
Fallback Functions: Implement securely, if used. Ensure correct handling of ether and gas limits. -
Check for potential gas limit issues with logging too many events. -
Verify that dependencies are pinned to specific, audited versions. - Minimize storage writes and reads.
- Evaluate loop usage and optimize for gas efficiency.
-
The interface should match fully the onchain ones.
Documentation
- Document functions and state variables using NatSpec comments.
- Provide an overview of the contract’s purpose and functionality.
❌ Missing - Add custom headers into the codebase with
Author
andReviewers
names:/// @custom:authors: [] /// @custom:reviewers: [] /// @custom:auditors: [] /// @custom:bounties: []
Testing and Verification
- Ensure comprehensive unit tests cover all scenarios and edge cases.
- Use Fuzzing in tests (1000 rounds)
- Using
modifier
&internal fn
in test to improve readability/reusability of tests -
Fuzzing ofstorage vars
andexternal call
methods -
Use invariant test if applicable (Use the technical doc where invariants should be defined) -
Use formal vefication if applicable (Use the technical doc where invariants should be defined) - Use static analysis tools (e.g., MythX, Slither) to detect common issues.
Adversarial Thinking
-
Hack the Code
- Think like an attacker and attempt to exploit vulnerabilities.
- Challenge assumptions and attempt to break the contract under different conditions.
-
Unpredictable System StatesConsider how the contract behaves under unpredictable states and stress conditions.Test for scenarios that might lead to unexpected behaviors.
-
List of Attack VectorsDonation Attacks: Review and protect against unintended ether donations.Flash Loans: Consider and mitigate risks from flash loan attacks.Oracle Manipulation: Ensure secure and reliable use of oracles to prevent manipulation.Gas Limit Exploits: Protect against attacks that exploit gas limits to disrupt contract functionality.Phishing and Social Engineering: Ensure contract interfaces are designed to minimize phishing risks.
Code Review Checklist
General Review Approach
- Understand the context
- Construct a mental model of the contract’s expected behavior.
- Compare the actual architecture to your mental model.
- Create a threat model and list high-level attack vectors.
-
Focus on functions handling value exchange (transfer
,send
,call
,delegatecall
,selfdestruct
). -
Review external contract interactions and validate assumptions. - Perform a line-by-line code review.
- Review from the perspective of every actor in the threat model.
- Evaluate test coverage and focus on untested areas.
Variables
- Visibility and Mutability
- Can it be
internal
? -
Can it beconstant
? -
Can it beimmutable
? - Is its visibility set?
- Document purpose and other important information using NatSpec.
- Can it be
- Storage Efficiency
- Can it be packed with adjacent storage variables?
-
Can it be packed in a struct with more than one other variable? -
Use full 256-bit types unless packing with other variables. -
If public array, is there a function to return the full array? - Use
private
only to prevent child contracts from accessing the variable, preferinternal
for flexibility.
Structs
-
Necessity and Documentation-
Is a struct necessary, or can variables be packed in storage? -
Are fields packed together if possible? -
Document purpose and all fields using NatSpec.
-
Functions
- Visibility and Functionality
- Can it be
external
?btor
❌rtob
❌
- Should it be
internal
?_rpow
✅
-
Should it bepayable
? -
Can it be combined with another similar function?
- Can it be
- Patterns and Security
-
Check for front-running possibilities, e.g.,approve
function. - Ensure return values are always assigned.
-
Test invariants about the state before function execution. -
Test invariants about return values and state changes after function execution. - Document all arguments, return values, and side effects using NatSpec.
❌ Found some issues detailed in the review -
If operating on another user, don’t assumemsg.sender
is the user.
-
Modifiers
- Safety and Documentation
- Avoid storage updates (except in reentrancy lock).
- Avoid external calls.
- Document purpose and information using NatSpec.
Code
- ~~Do not mutate state before doing external calls to unknown contract ~~
- Safe Math and Efficiency
- Use SafeMath or 0.8 checked math
-
unchecked
blocks MUST contain a justification
-
- Minimize redundant storage reads.
- Avoid unbounded loops/arrays causing DoS
- Use SafeMath or 0.8 checked math
- Best Practices
-
Useblock.timestamp
only for long intervals -
Avoiddelegatecall
especially to external contracts -
Avoid updating array length while iterating. -
Useabi.encode()
instead ofabi.encodePacked()
with dynamic types -
Don’t assume a specific ETH balance -
Remember private data isn't private - Don’t mutate function parameters.
- Compare costs of calculating vs storing values.
- Multiply before dividing unless multiplication could overflow.
- Replace magic numbers with constants.
-
Consider DoS if recipient’s fallback function reverts. -
Safely check return values of ERC20 transfers. -
Avoidmsg.value
in loops. -
Avoidmsg.value
if recursive delegatecalls are possible. -
Don’t rely onmsg.sender
in your logic if your contract can be called asdelegate
call. -
Try to avoid using send funds logic use pull funds logic instead(see next check) -
Try to avoid usingpayable.transfer()
, usepayable.call{value: }()
(be aware of reentrancy) orpayable.send()
instead depending on use case -
Useunchecked
blocks where safe, and document reasons with gas estimates. - Use parentheses to emphasize arithmetic operator precedence.
-
Document precision loss in arithmetic operations and ensure it benefits the right actors.
-
- Go over the solodit.xyz/checklist
ℹ️ Most checks don't apply, the ones who do are already covered in this checklist (i.e: SOL-Basics-Function-7)
Yes, lower runs optimize for deployment, a larger number of runs for execution. I was fighting deployment size at one point (to try to fit rates up to 60% within contract size limit), this is why 1 runs. Now we can remove it, deployment size and gas cost are quite close, but it does have a large impact on read gas cost (~600 gas difference, from 3767 top 3123 (or 3111 with 200 runs). What do you think @amusingaxl ? Edit: changed it to 200 runs as it is more conventional, and it results in the best read price (deployment difference from using 1 run is negligible and we're not fighting the size limit at 5k BPS |
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
What if we set I'm using the gas metering script. With
With
Not sure how accurate those are though. |
We can do it. These results are accurate, the difference will be exactly that. Only thing that need to be noted is these are prices for reading from a warm slot, so for cold slots the cost is the listed value + 2000. |
That was what I was wondering. |
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
It's due to running it within a script. On tests, the constructor and Only way to get cold slot gas cost would be pointing the script to a testnet and running it with |
No need, let's keep it as it is. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found 2 additional nits.
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
Co-authored-by: amusingaxl <[email protected]> Signed-off-by: oddaf <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
No description provided.