-
Notifications
You must be signed in to change notification settings - Fork 1
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
[WIP] Full Code Review #24
base: review/full
Are you sure you want to change the base?
Conversation
Adding hardhat-keystore
Parse trace logs
… console). Retry in case of rate limit
feat: use cache only if it's enabled + refactor
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) from 6.2.2 to 6.3.0. - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](pillarjs/path-to-regexp@v6.2.2...v6.3.0) --- updated-dependencies: - dependency-name: path-to-regexp dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]>
…to-regexp-6.3.0 build(deps): bump path-to-regexp from 6.2.2 to 6.3.0
Depot docs review
function isValid(bytes: unknown): bytes is HexStr { | ||
if (typeof bytes !== "string") return false; | ||
const stripped = strip0x(bytes); | ||
return stripped.length % 2 === 0 && /^[a-fA-f0-9]+$/.test(strip0x(bytes)); |
Check warning
Code scanning / CodeQL
Overly permissive regular expression range Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix AI about 1 month ago
To fix the problem, we need to correct the regular expression to ensure it only matches valid hexadecimal characters. The best way to do this is to replace the overly permissive range A-f
with the correct range A-F
. This change will ensure that the regular expression only matches characters in the ranges 0-9
, a-f
, and A-F
.
- General fix: Replace the incorrect range
A-f
with the correct rangeA-F
. - Detailed fix: Update the regular expression on line 68 in the file
src/common/bytes.ts
to useA-F
instead ofA-f
. - Specific changes: Modify the regular expression in the
isValid
function to/^[a-fA-F0-9]+$/
. - Requirements: No additional methods, imports, or definitions are needed to implement this change.
-
Copy modified line R68
@@ -67,3 +67,3 @@ | ||
const stripped = strip0x(bytes); | ||
return stripped.length % 2 === 0 && /^[a-fA-f0-9]+$/.test(strip0x(bytes)); | ||
return stripped.length % 2 === 0 && /^[a-fA-F0-9]+$/.test(strip0x(bytes)); | ||
} |
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.
TL;DR
- Overall, the code is good, with several improvements of varying severity suggested, mostly aimed at improving the quality of API usage
- Most of the decisions made by the project authors are reasonable and in line with the project's objectives
- Two critical issues have been identified that require particular attention:
Note
Severity ratings:
🔴 - HIGH
🟡 - MEDIUM
👍 - GOOD IDEA
API Design
Requirements
APIs should be simple, concise, and easy to use. API should remain minimalist to reduce the amount of code the user must write. The framework should encapsulate complex logic to simplify API usage. Functions and objects should have descriptive names that clearly reflect their purpose and usage.
Review Points
Check that API functions and parameters are self-explanatory and require minimal documentation. Look for any extraneous methods or properties that could be removed or encapsulated within the framework. Look for areas where logic could be encapsulated, such as transaction handling or error management.
Findings
The project appears to be logically structured, with modular directories organised by functionality, including configurations, contracts, keystores, voting and trace handling, which helps with navigation and finding specific functionality. The naming conventions are generally well aligned with the expected functionality (e.g. providers, omnibuses, traces). Some directories, such as `omnibuses', contain broad functionality (e.g. tools, checks, blueprints) which might benefit from more granular sub-modules to clarify purpose at a glance. Moreover, enhancing function and parameter names, as suggested, will make the API more intuitive, leading to easier adoption and fewer errors during implementation. See code-related findings tagged with [API Design].
Error Prevention
Requirements
APIs should be bug-proof with no room for ambiguity, making it difficult for developers to misunderstand them. Design APIs to prevent misuse using intuitive naming conventions.
Review Points
Ensure that all API functions handle errors gracefully, with clear messages or error types for developers. Evaluate whether all exposed functions are logically grouped and that any complex functionality is encapsulated to simplify usage.
Findings
The codebase uses custom error classes, error handling and type-safe definitions. However, improvements could be made by extending the use of exhaustive checks for unsupported conditions. This would make the APIs more resilient to misuse and minimize potential edge cases that could lead to unhandled errors. See code-related findings tagged with [Error Prevention].
Code Quality
Requirements
Ensure robust TypeScript type definitions across the codebase to catch potential type errors at compile time. Each API function should include concise documentation outlining usage, parameters, and any edge cases.
Review Points
Check that all functions and variables are appropriately typed and that type inference is used wherever possible. Ensure function and module-level documentation is present and clear.
Findings
Overall, typing and type inference are used effectively within the project, with little room for improvement. The design seems to focus on encapsulating complex interactions. The presence of README files and examples of configuration files indicates some attention to usability. However, many files lack module and/or function level documentation, it may not be extremely useful to document everything, but focus on API documentation should be a priority. See code-related findings tagged with [Code Quality].
Testing
Requirements
The code should be rigorously tested, focusing on API behaviour under various edge cases. Where applicable, tests should mock Ethereum transactions to simulate and validate API behaviour.
Review Points
Ensure that tests cover a wide range of scenarios, including edge cases, expected behaviour and potential misuse. Verify that tests include mock transactions to ensure that the framework behaves predictably under simulated conditions.
Findings
It looks like mock data and utilities, including stubs and simulated transaction environments, are being used effectively. It is important to control test coverage and increase it from 60% to 80%+.
As a general suggestion, clear guidelines and conventions should be introduced for writing both omnibuses and, more importantly, tests.
Ability to run omnibus items one-by-one will decrease development time
|
||
export type ChainId = "1" | "5"; | ||
export type ChainName = "eth" | "arb" | "opt"; | ||
export type NetworkName = "mainnet" | "goerli"; |
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.
[Code Quality] 🔴
Using the NetworkName
type here for validation is good, but I suggest going further:
introduce the constants "mainnet"
and "goerli"
so that they can be referenced without having to type a string literal each time.
The same should be probably valid for ChainId
and ChainName
types.
|
||
const NETWORKS: Record<ChainName, Record<NetworkName, Network>> = { | ||
eth: { | ||
mainnet: new Network("mainnet", 1), |
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.
[Code Quality] 🔴
String literals should be replaced by constants here and everywhere else.
import { call, event } from "../src/votes"; | ||
|
||
export default omnibuses.create({ | ||
network: "mainnet", |
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.
[Code Quality] 🔴
The constant (to be introduced in src/networks.ts) should be used here instead of the string literal.
|
||
export default omnibuses.create({ | ||
network: "mainnet", | ||
// launchedOn: 12345678, // Launch block number should be set only if omnibus was successfully launched. |
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.
[API Design]
The following fields:
launchedOn, voteId, executedOn, quorumReached
should be set separately from the original omnibus plan being written and tested.
These fields should be separated into a different entity, as it is currently misleading as to how and when these params should be set, as they modify the original object being tested. Ideally, it should be possible to call separate callback-style functions such as omnibusStarted(voteId)
etc. to give a clear timeline and explicit control over the omnibus object. These functions will modify the omnibus object internally.
// launchedOn: 12345678, // Launch block number should be set only if omnibus was successfully launched. | ||
// voteId: 000, // Vote ID should be set only if omnibus is already started. | ||
// executedOn: 12345678, // Execution block number should be set only if vote is passed and omnibus was successfully executed. | ||
quorumReached: false, // Should be set to true if quorum was reached during the vote. |
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.
[API Design]
It should be considered to rethink the name and purpose of this field, as omnibuses are run until the quorum is reached, so there is no way that the final state could be quorumReached: false
.
/** | ||
* Contains the info about the omnibus launching - the number of the block where the omnibus was launched. | ||
*/ | ||
launchedOn?: number | undefined; |
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.
[API Design] 🔴
launchedOn
and executedOn
should be renamed to include context, e.g., launchedOnBlock, executedOnBlock. Correct terminology should be used, launch and execute are words with a similar meaning, probably enact would work better here?
import { RpcProvider } from "./types"; | ||
import { isHardhatEthersProvider, isJsonRpcProvider, UnsupportedProviderError } from "./utils"; | ||
|
||
function provider(runner: ContractRunner): RpcProvider { |
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.
[Code Quality] 🟡
A validateRpcProvdier
should be more suitable here to clearly indicate that the function is validating and returning a specific type of provider.
const { easyTrack, callsScript, voting } = contracts; | ||
return { | ||
title: title, | ||
evmCall: call(easyTrack.removeEVMScriptFactory, [factory]), |
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.
[Error Prevention] 🟡
rename call
?
contracts: Contracts<Lido>, | ||
{ factory, title }: RemovePaymentEvmScriptFactoryInput, | ||
): OmnibusItem { | ||
const { easyTrack, callsScript, voting } = contracts; |
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.
[Error Prevention] 🟡
Do we need to validate input here?
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.
Check factory, title
against common mistakes (0 address, etc.)
} | ||
} | ||
|
||
function checkEnvVars() { |
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.
[Error Prevention]
Is it enough to check only one var? I suggest checking vars when running tests too
fix: update WHALE, remove outdated item, fix readme link
API-centered code review of the Depot project