Skip to content
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

Tests on client code #1

Open
wants to merge 127 commits into
base: develop
Choose a base branch
from
Open

Tests on client code #1

wants to merge 127 commits into from

Conversation

F-WRunTime
Copy link
Owner

No description provided.

F-WRunTime and others added 30 commits July 5, 2024 15:17
…unctionality reuse.

* KontrolTest has basic helper functions, such as _establish and _storeUInt256, etc.
* StorageSetup has the ...StorageSetup functions, refactored to receive the relevant contracts as parameters.
* DualGovernanceSetUp has the storage variables for tests of the DualGovernance contract and the setUp function initializing them.
Copy link

coderabbitai bot commented Oct 7, 2024

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • .github/workflows/lido-ci.yml is excluded by !**/*.yml

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough
📝 Walkthrough

Walkthrough

The pull request introduces several modifications across multiple Solidity contracts and test files. Key changes include the enhancement of method signatures in the IStETH interface, updates to the DualGovernanceState library for improved logic, and the introduction of new contracts such as EscrowModel, StETHModel, and WstETHAdapted. Additionally, various test contracts have been added to validate the functionality of the dual governance system, escrow operations, and veto mechanisms. Overall, the changes focus on refining existing functionalities and adding new features to improve the governance and escrow processes.

Changes

File Path Change Summary
contracts/interfaces/IStETH.sol Updated transferShares method to return uint256. Added sharesOf method for querying shares of an account.
contracts/libraries/DualGovernanceState.sol Added Math library import, modified conditions in _isFirstSealRageQuitSupportCrossed and _isSecondSealRageQuitSupportCrossed to use >=, refactored _isVetoSignallingReactivationDurationPassed, and adjusted _calcDynamicTimelockDuration logic.
contracts/libraries/WithdrawalBatchesQueue.sol Moved Status enum inside WithdrawalsBatchesQueue library.
contracts/model/DualGovernanceModel.sol Renamed contract from DualGovernance to DualGovernanceModel, updated state variable types, and modified constructor and several functions to accommodate new model classes. Made fromRageQuit function public.
contracts/model/EmergencyProtectedTimelockModel.sol Renamed contract from EmergencyProtectedTimelock to EmergencyProtectedTimelockModel. Updated cancelAllNonExecutedProposals function to check for nextProposalId > 0.
contracts/model/EscrowModel.sol Introduced EscrowModel contract with enumerations and state variables for managing escrow operations, including locking and unlocking tokens, withdrawal requests, and claiming withdrawals.
contracts/model/StETHModel.sol Added StETHModel contract implementing IStETH for managing pooled Ether and shares with several state variables and functions for token management.
contracts/model/WithdrawalQueueModel.sol Introduced WithdrawalQueueModel with constants for minimum and maximum withdrawal amounts and a function to retrieve the last finalized request ID.
contracts/model/WstETHAdapted.sol Added WstETHAdapted contract for wrapping stETH tokens, implementing ERC20Permit standard, and providing wrap/unwrap functionality.
lib/kontrol-cheatcodes Updated subproject commit reference.
test/kontrol/ActivateNextState.t.sol Introduced testing contract for dual governance state transitions, including assertions for state integrity.
test/kontrol/DualGovernanceSetUp.sol Added setup contract for initializing dual governance components and storage states.
test/kontrol/EscrowAccounting.t.sol Added test contract for validating escrow system functionality, including withdrawal requests and accounting records.
test/kontrol/EscrowInvariants.sol Introduced contract for validating invariants related to escrow operations.
test/kontrol/EscrowLockUnlock.t.sol Added test contract for locking and unlocking stETH within the escrow system.
test/kontrol/EscrowOperations.t.sol Introduced contract for testing various escrow operations, including locking and unlocking stETH under specific conditions.
test/kontrol/KontrolTest.sol Added testing contract with structured assertions and low-level storage manipulation functions.
test/kontrol/ProposalOperations.t.sol Introduced contract for testing proposal operations within dual governance, including validation functions and test cases.
test/kontrol/ProposalOperationsSetup.sol Added setup contract for managing proposal operations and storage.
test/kontrol/RageQuit.t.sol Introduced test contract for verifying behavior during the Rage Quit state.
test/kontrol/StorageSetup.sol Added contract for managing storage setup and validation for governance and escrow functionalities.
test/kontrol/VetoCooldown.t.sol Introduced test contract for validating veto cooldown mechanisms within dual governance.
test/kontrol/VetoSignalling.t.sol Refactored contract to utilize new setup through DualGovernanceSetUp, updating state management and test functions accordingly.
test/kontrol/lido-lemmas.k Updated LIDO-LEMMAS module to enhance arithmetic capabilities and logical comparisons.
test/kontrol/scripts/common.sh Modified usage functions and argument parsing logic for improved clarity and Docker management.
test/kontrol/scripts/run-kontrol.sh Simplified kontrol_build and kontrol_prove functions by removing numerous command-line options and streamlining logging.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant EscrowModel
    participant DualGovernanceModel

    User->>EscrowModel: lock(amount)
    EscrowModel->>User: confirm lock
    User->>EscrowModel: unlock()
    EscrowModel->>User: confirm unlock
    User->>DualGovernanceModel: submitProposal(details)
    DualGovernanceModel->>User: confirm proposal submission
    User->>DualGovernanceModel: activateNextState()
    DualGovernanceModel->>User: confirm state activation
Loading

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 56

🧹 Outside diff range and nitpick comments (32)
contracts/model/WithdrawalQueueModel.sol (3)

7-7: Consider initializing _lastFinalizedRequestId and adding a comment.

The _lastFinalizedRequestId variable is crucial for tracking withdrawal requests. Consider the following suggestions:

  1. Initialize it explicitly (e.g., to 0 or another appropriate starting value) to make the initial state clear.
  2. Add a comment explaining its purpose and any assumptions about its value range.

Example:

/// @dev Tracks the ID of the last finalized withdrawal request. Starts at 0 and increases monotonically.
uint256 private _lastFinalizedRequestId = 0;

This improves code readability and helps prevent potential misunderstandings about the variable's intended use.


9-11: LGTM: Add natspec documentation to the function.

The getLastFinalizedRequestId function is well-implemented, providing controlled access to the private state variable. To improve documentation and developer experience, consider adding natspec comments:

/// @notice Returns the ID of the last finalized withdrawal request
/// @return The last finalized request ID
function getLastFinalizedRequestId() external view returns (uint256) {
    return _lastFinalizedRequestId;
}

This addition will enhance the contract's readability and provide better context for developers interacting with the contract.


1-12: Consider adding functionality to update _lastFinalizedRequestId.

The WithdrawalQueueModel contract provides a good foundation for managing STETH withdrawal limits and tracking finalized requests. However, it's missing functionality to update the _lastFinalizedRequestId. Consider adding a function like:

function updateLastFinalizedRequestId(uint256 newId) external onlyAuthorized {
    require(newId > _lastFinalizedRequestId, "New ID must be greater than current");
    _lastFinalizedRequestId = newId;
}

Ensure to implement proper access control (e.g., onlyAuthorized modifier) to prevent unauthorized updates. This addition would complete the basic functionality expected from this contract.

Also, consider adding events to log important state changes, which can be useful for off-chain services and improved transparency.

Would you like assistance in implementing these suggestions or creating related test cases?

contracts/interfaces/IStETH.sol (2)

18-18: Approve the addition of sharesOf function.

The new sharesOf function is a valuable addition to the interface. It allows querying the number of shares held by a specific account, which enhances the overall functionality of the contract.

Consider adding a NatSpec comment to document the purpose and behavior of this function. For example:

/// @notice Returns the number of shares owned by the specified account
/// @param _account The address of the account to query
/// @return The number of shares owned by the account
function sharesOf(address _account) external view returns (uint256);

Line range hint 1-20: Overall assessment: Changes enhance the IStETH interface.

The modifications to this interface file are well-structured and improve its functionality. The addition of a return value to transferShares and the new sharesOf function provide more capabilities to interacting contracts. These changes align well with the PR objective of enhancing tests on client code, as they allow for more comprehensive testing of share-related operations.

As you continue to develop this system, consider the following:

  1. Ensure that all functions in this interface have clear, consistent error handling mechanisms.
  2. If not already present, consider adding events for significant state changes to facilitate off-chain tracking and improve transparency.
  3. As the interface grows, you might want to consider splitting it into smaller, more focused interfaces if it becomes too large or if certain functions are only used by specific types of clients.
test/kontrol/RageQuit.t.sol (2)

1-8: LGTM! Consider adding NatSpec comments.

The contract declaration and imports look good. The use of an up-to-date Solidity version (0.8.23) is commendable. The inheritance from DualGovernanceSetUp suggests good test organization.

Consider adding NatSpec comments to describe the purpose of the RageQuitTest contract. This would improve documentation and make the test's intent clearer.


9-20: Good test structure. Consider enhancing test coverage.

The testRageQuitDuration function is well-structured and clearly tests the RageQuit duration logic. However, there are a few areas where the test coverage could be improved:

  1. The test only asserts the state when the timestamp is within the RageQuit duration. Consider adding an assertion for the case when the timestamp is beyond this duration.

  2. The test assumes the initial state is RageQuit but doesn't verify this assumption. It might be beneficial to assert this condition explicitly.

  3. The test activates the next state but doesn't verify what this next state is. It might be useful to check if the state changes as expected when outside the RageQuit duration.

Here's a suggested improvement to enhance the test coverage:

 function testRageQuitDuration() external {
     vm.assume(dualGovernance.getCurrentState() == State.RageQuit);
+    assert(dualGovernance.getCurrentState() == State.RageQuit, "Initial state should be RageQuit");

     dualGovernance.activateNextState();

     uint40 rageQuitTimelockStartedAt = _getRageQuitTimelockStartedAt(rageQuitEscrow);
     uint32 rageQuitExtensionDelay = _getRageQuitExtensionDelay(rageQuitEscrow);

     if (block.timestamp <= rageQuitTimelockStartedAt + rageQuitExtensionDelay) {
         assert(dualGovernance.getCurrentState() == State.RageQuit, "State should remain RageQuit within duration");
+    } else {
+        assert(dualGovernance.getCurrentState() != State.RageQuit, "State should change after RageQuit duration");
     }
 }

This change adds assertions to verify the initial state and the state transition after the RageQuit duration, providing more comprehensive test coverage.

test/kontrol/VetoCooldown.t.sol (1)

12-22: Add comments to improve code readability.

Consider adding comments to explain the purpose of each step in the test. This will make the test easier to understand and maintain. For example:

function testVetoCooldownDuration() external {
    // Ensure the initial state is VetoCooldown
    vm.assume(dualGovernance.getCurrentState() == State.VetoCooldown);

    // Calculate the maximum cooldown duration
    Timestamp timeEnteredAt = Timestamp.wrap(_getEnteredAt(dualGovernance));
    Timestamp maxCooldownDuration = addTo(config.VETO_COOLDOWN_DURATION(), timeEnteredAt);

    // Attempt to activate the next state
    dualGovernance.activateNextState();

    // Check if we're still in VetoCooldown and if the duration has elapsed
    bool stillInVetoCooldown = (dualGovernance.getCurrentState() == State.VetoCooldown);
    bool durationHasElapsed = (Timestamps.now() > maxCooldownDuration);

    // Assert that we're not in VetoCooldown if and only if the duration has elapsed
    assert(stillInVetoCooldown != durationHasElapsed);
}
test/kontrol/scripts/run-kontrol.sh (1)

37-38: Consider quoting $LOG_PATH and the implications of suppressing tar output.

  1. On lines 37-38, consider adding quotes around $LOG_PATH to handle paths with spaces:
-    if [ ! -d $LOG_PATH ]; then
-      mkdir $LOG_PATH
+    if [ ! -d "$LOG_PATH" ]; then
+      mkdir "$LOG_PATH"
  1. On line 48, suppressing tar output might hide potential errors. Consider redirecting stderr to a log file instead of /dev/null:
-      tar -xzvf "$RESULTS_LOG" > /dev/null 2>&1
+      tar -xzvf "$RESULTS_LOG" > /dev/null 2>> "$LOG_PATH/tar_errors.log"

This way, you can still check for any extraction errors if needed.

Also applies to: 48-48

test/kontrol/scripts/common.sh (3)

Line range hint 175-181: LGTM with a suggestion: Consider adding error handling

The changes to the clean_docker function simplify the process and potentially improve reliability by adding a small delay after stopping the container. This is a good improvement.

However, consider adding error handling for the docker stop command. For example:

if ! docker stop "$CONTAINER_NAME" > /dev/null 2>&1; then
  notif "Failed to stop container $CONTAINER_NAME"
fi

This would provide more informative feedback if the stop operation fails.


Line range hint 35-181: LGTM with a suggestion: Consider using boolean values consistently

The updates to the argument parsing and execution mode selection logic are well-implemented and improve the script's robustness. The handling of different scenarios (container, local, dev, script, custom tests) is now more comprehensive.

One small suggestion for improvement:
Consider using true and false consistently for boolean variables instead of mixing string comparisons and boolean values. For example, replace:

if [ "$LOCAL" = false ]; then

with:

if [ "$LOCAL" = "false" ]; then

This would make the code more consistent and potentially less error-prone.


Line range hint 92-124: LGTM with a suggestion: Consider refactoring for improved readability

The updates to the parse_first_arg function significantly improve the script's flexibility, particularly in handling different test execution scenarios. The new logic for the "script" argument is a valuable addition.

However, the function's complexity has increased. Consider refactoring it to improve readability and maintainability. For example:

  1. Extract the logic for each argument type into separate functions.
  2. Use a case statement instead of multiple if-elif blocks.
  3. Consider using associative arrays to map arguments to their corresponding actions.

This refactoring could make the code easier to understand and maintain in the future.

test/kontrol/DualGovernanceSetUp.sol (1)

49-55: Ensure consistent naming in storage labels for better readability

The storage labels transition from // ?STORAGE to // ?STORAGE0. For clarity and consistency, consider updating the first storage label to // ?STORAGE0 or adjust subsequent labels accordingly.

contracts/model/WstETHAdapted.sol (4)

79-85: Remove unnecessary commented-out code

There is a commented-out receive function present in the contract. If this code is not intended for future use, consider removing it to keep the codebase clean and maintainable.

Apply this diff to remove the commented-out code:

 /*
 receive() external payable {
     uint256 shares = stETH.submit{value: msg.value}(address(0));
     _mint(msg.sender, shares);
 }
 */

114-114: Correct typo in the documentation comment

In the return description of the tokensPerStEth function, remove the unnecessary article "a" for clarity.

Apply this diff:

  * @return Amount of wstETH for a 1 stETH
- * @return Amount of wstETH for a 1 stETH
+ * @return Amount of wstETH for 1 stETH

42-43: Improve wording in documentation comment

Consider updating the description to "Exchanges stETH for wstETH" for clearer wording.

Apply this diff:

  * @notice Exchanges stETH to wstETH
- * @notice Exchanges stETH to wstETH
+ * @notice Exchanges stETH for wstETH

61-62: Improve wording in documentation comment

Consider updating the description to "Exchanges wstETH for stETH" for clearer wording.

Apply this diff:

  * @notice Exchanges wstETH to stETH
- * @notice Exchanges wstETH to stETH
+ * @notice Exchanges wstETH for stETH
contracts/model/StETHModel.sol (2)

74-79: Clarify error message in decreaseAllowance function

The error message "ALLOWANCE_BELOW_ZERO" in the decreaseAllowance function may be misleading. It suggests that the allowance itself is below zero, which is impossible since uint256 variables cannot be negative. The actual issue is that the subtraction would result in a negative allowance.

Consider updating the error message to more accurately reflect the condition:

 uint256 currentAllowance = allowances[msg.sender][_spender];
-    require(currentAllowance >= _subtractedValue, "ALLOWANCE_BELOW_ZERO");
+    require(currentAllowance >= _subtractedValue, "DECREASED_ALLOWANCE_BELOW_ZERO");

4-4: Ensure comprehensive documentation and comments

While the code includes some comments, adding NatSpec documentation for public and external functions can improve code readability and facilitate usage by other developers and tools.

Consider adding function-level comments using the Ethereum Natural Specification Format (NatSpec):

+/// @notice Sets the total pooled Ether
+/// @param _value The new total pooled Ether value
 function setTotalPooledEther(uint256 _value) external onlyOwner {

Apply similar documentation to other functions.

test/kontrol/EscrowAccounting.t.sol (2)

45-47: Remove or Clarify Obscure Comments

The comments // ?WORD: totalPooledEther, // ?WORD0: totalShares, and // ?WORD1: shares[escrow] are unclear and may confuse readers. They do not provide meaningful information about the code and may clutter the codebase.

Consider removing these comments or replacing them with descriptive comments that clarify their purpose.


58-67: Clarify the Purpose of Sequential Comments with '?WORD' Prefix

The comments from lines 58 to 67 (e.g., // ?WORD4: lockedShares, // ?WORD5: claimedETH, etc.) are not standard and may be confusing. These comments appear to reference storage slots or symbolic variables without clear context.

Please clarify the intent of these comments or remove them if they are not necessary. If they are placeholders or references for symbolic execution tools, consider documenting their purpose for future maintainability.

test/kontrol/EscrowOperations.t.sol (1)

115-162: Offer assistance: Implement 'testCannotWithdrawBeforeEthClaimTimelockElapsed'

The test function testCannotWithdrawBeforeEthClaimTimelockElapsed is currently commented out with a TODO note to adapt it to the client code.

Would you like assistance in adapting this test function to the current codebase? I can help implement the required changes to ensure the test accurately verifies that a user cannot withdraw funds before the RageQuitEthClaimTimelock has elapsed.

test/kontrol/ProposalOperationsSetup.sol (3)

23-63: Add function comments to _initializeAuxDualGovernance() to explain its purpose and implementation details.

The _initializeAuxDualGovernance() function performs complex initialization involving direct storage manipulation and bitmask operations. Adding a detailed function comment explaining its purpose, the rationale behind the storage manipulations, and any assumptions will enhance code readability and maintainability.


167-171: Add comments to explain storage slot calculations in _getProposalsSlot().

The _getProposalsSlot() function uses specific calculations involving magic numbers to compute storage slots. Adding comments to explain the logic behind these calculations and the significance of the numbers used will enhance code readability.


83-94: Clarify the purpose of inline assembly when storing slot 3.

In lines 83 to 94, inline assembly is used to manipulate and store a bytes32 value into storage. Providing comments to explain what slot3Abi represents and detailing the steps within the assembly block will help maintainers understand the code's intent.

test/kontrol/lido-lemmas.k (2)

49-71: Consider removing or documenting large blocks of commented-out code

Lines 49-71 contain a sizeable block of commented-out code related to the [create-valid-enhanced] rule. If this code is deprecated or no longer necessary, consider removing it to improve code clarity. If it's meant to be retained for future reference, adding a comment explaining its purpose would be beneficial.


135-135: Maintain consistent variable naming conventions

At line 135, variables _WORD4:Int and _WORD3:Int are used with leading underscores, whereas elsewhere, variables like WORD4:Int are used without underscores. For consistency and readability, consider standardizing the variable naming convention throughout the code.

test/kontrol/EscrowLockUnlock.t.sol (1)

245-251: Clean up commented-out assertions to maintain code quality.

There are commented-out assertions between lines 245 and 251. If these assertions are no longer needed, consider removing them. If they are kept intentionally, add comments explaining their purpose.

contracts/model/DualGovernanceModel.sol (3)

56-56: Potential inconsistency in parameter naming

In the constructor, the parameter is named emergencyProtectionTimelock, but the state variable is emergencyProtectedTimelock. For clarity and consistency, consider aligning the parameter name with the state variable.

Suggested change:

-constructor(address _fakeETH, uint256 emergencyProtectionTimelock) {
+constructor(address _fakeETH, uint256 _emergencyProtectedTimelock) {
     currentState = State.Normal;
     lastStateChangeTime = block.timestamp;
     fakeETH = _fakeETH;
-    emergencyProtectedTimelock = new EmergencyProtectedTimelockModel(address(this), emergencyProtectionTimelock);
+    emergencyProtectedTimelock = new EmergencyProtectedTimelockModel(address(this), _emergencyProtectedTimelock);
     signallingEscrow = new EscrowModel(address(this), _fakeETH);
 }

191-194: Redundant timestamp checks

The require statements:

require(lastStateChangeTime <= block.timestamp);
require(lastSubStateActivationTime <= block.timestamp);
require(lastStateReactivationTime <= block.timestamp);

These checks may be redundant since it's unlikely for these timestamps to be in the future under normal conditions. Removing them could save gas and simplify the code.


240-247: Simplify conditional logic involving timestamps

In the conditions:

if (
    block.timestamp != lastStateChangeTime
    && block.timestamp - lastStateChangeTime > DYNAMIC_TIMELOCK_MAX_DURATION
    && rageQuitSupport > SECOND_SEAL_RAGE_QUIT_SUPPORT
) { /* ... */ }

if (
    block.timestamp != lastStateChangeTime
    && block.timestamp - lastStateChangeTime > calculateDynamicTimelock(rageQuitSupport)
    && block.timestamp - Math.max(lastStateChangeTime, lastStateReactivationTime) > VETO_SIGNALLING_MIN_ACTIVE_DURATION
) { /* ... */ }

The check block.timestamp != lastStateChangeTime might be unnecessary because the subsequent condition block.timestamp - lastStateChangeTime > X would be false when the timestamps are equal.

Consider removing block.timestamp != lastStateChangeTime to simplify the condition.

test/kontrol/VetoSignalling.t.sol (1)

251-274: Clarify complex control flow with additional comments.

The control flow within the if statements from lines 251-274 is intricate and may benefit from additional comments explaining each branch's purpose. This will aid in understanding and maintaining the code in the future.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 7cebc78 and d48291a.

⛔ Files ignored due to path filters (4)
  • .github/workflows/lido-ci.yml is excluded by !**/*.yml
  • foundry.toml is excluded by !**/*.toml
  • kontrol.toml is excluded by !**/*.toml
  • test/kontrol/scripts/versions.json is excluded by !**/*.json
📒 Files selected for processing (26)
  • contracts/interfaces/IStETH.sol (1 hunks)
  • contracts/libraries/DualGovernanceState.sol (4 hunks)
  • contracts/libraries/WithdrawalBatchesQueue.sol (1 hunks)
  • contracts/model/DualGovernanceModel.sol (14 hunks)
  • contracts/model/EmergencyProtectedTimelockModel.sol (2 hunks)
  • contracts/model/EscrowModel.sol (1 hunks)
  • contracts/model/StETHModel.sol (1 hunks)
  • contracts/model/WithdrawalQueueModel.sol (1 hunks)
  • contracts/model/WstETHAdapted.sol (1 hunks)
  • lib/kontrol-cheatcodes (1 hunks)
  • test/kontrol/ActivateNextState.t.sol (1 hunks)
  • test/kontrol/DualGovernanceSetUp.sol (1 hunks)
  • test/kontrol/EscrowAccounting.t.sol (1 hunks)
  • test/kontrol/EscrowInvariants.sol (1 hunks)
  • test/kontrol/EscrowLockUnlock.t.sol (1 hunks)
  • test/kontrol/EscrowOperations.t.sol (1 hunks)
  • test/kontrol/KontrolTest.sol (1 hunks)
  • test/kontrol/ProposalOperations.t.sol (1 hunks)
  • test/kontrol/ProposalOperationsSetup.sol (1 hunks)
  • test/kontrol/RageQuit.t.sol (1 hunks)
  • test/kontrol/StorageSetup.sol (1 hunks)
  • test/kontrol/VetoCooldown.t.sol (1 hunks)
  • test/kontrol/VetoSignalling.t.sol (7 hunks)
  • test/kontrol/lido-lemmas.k (4 hunks)
  • test/kontrol/scripts/common.sh (2 hunks)
  • test/kontrol/scripts/run-kontrol.sh (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • lib/kontrol-cheatcodes
🧰 Additional context used
🪛 Shellcheck
test/kontrol/scripts/run-kontrol.sh

[warning] 16-16: GHCRTS appears unused. Verify use (or export if used externally).

(SC2034)

🔇 Additional comments (45)
contracts/model/WithdrawalQueueModel.sol (2)

1-1: LGTM: Pragma statement is appropriate.

Using a specific, recent Solidity version (0.8.23) is a good practice. It ensures consistency across different environments and takes advantage of the latest language features and bug fixes.


4-5: Consider increasing the MIN_STETH_WITHDRAWAL_AMOUNT.

The current minimum withdrawal amount of 100 wei (approximately 1.8e-16 STETH) seems impractically low for real-world use. Consider increasing this to a more meaningful value to prevent dust amounts and reduce unnecessary transactions.

The use of constants for these limits is excellent for gas optimization and easier future updates. Ensure these values align with your business requirements and economic model.

To verify the appropriateness of these constants, please run the following script:

contracts/interfaces/IStETH.sol (1)

12-12: Approve the addition of return value to transferShares.

The updated function signature now includes a uint256 return value, which is a good improvement. This change provides more information to the caller, potentially the number of shares transferred or another relevant value.

Please ensure that the implementation of this function and any contracts calling it have been updated accordingly. Run the following script to check for potential inconsistencies:

test/kontrol/VetoCooldown.t.sol (1)

1-10: LGTM: File structure and imports are well-organized.

The file structure is clean, and the imports are appropriate for the test's functionality. The use of the latest Solidity version (0.8.23) is commendable.

test/kontrol/scripts/run-kontrol.sh (4)

70-70: Good addition of TERM signal to the trap command.

Adding the TERM signal to the trap command is a positive change. It allows the script to handle termination signals gracefully, improving its robustness.


24-28: Simplified kontrol_prove function looks good, but verify impact.

The kontrol_prove function has been simplified in the same manner as kontrol_build. This consistency is good for maintainability. However, please ensure that:

  1. The removed options are not necessary for the prove process.
  2. If the options are still needed, they are set elsewhere (e.g., in a configuration file).

To check if the removed options are used elsewhere, run:

#!/bin/bash
# Description: Search for previously used kontrol prove options in shell scripts
rg --type sh '(run kontrol prove.*--verbose|--require|--module-import|--max-depth|--max-iterations|--smt-timeout|--workers)' .

16-21: Simplified kontrol_build function looks good, but verify impact.

The kontrol_build function has been significantly simplified by removing all command-line options. While this improves readability, please ensure that:

  1. The removed options are not necessary for the build process.
  2. If the options are still needed, they are set elsewhere (e.g., in a configuration file).

To check if the removed options are used elsewhere, run:

#!/bin/bash
# Description: Search for previously used kontrol build options in shell scripts
rg --type sh '(run kontrol build.*--verbose|--require|--module-import|--max-depth|--max-iterations|--smt-timeout|--workers)' .
🧰 Tools
🪛 Shellcheck

[warning] 16-16: GHCRTS appears unused. Verify use (or export if used externally).

(SC2034)


16-16: Verify the usage of the GHCRTS variable.

The GHCRTS variable is declared but appears to be unused in the visible parts of the script. If it's not used elsewhere, consider removing it to improve code clarity.

To check for any usage of GHCRTS in the project, run the following command:

✅ Verification successful

GHCRTS variable is unused and can be removed.

The GHCRTS variable is declared in run-kontrol.sh but is not used anywhere else in the script or the codebase. Removing it will improve code clarity.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for usage of GHCRTS variable in shell scripts
rg --type sh 'GHCRTS' .

Length of output: 128


Script:

#!/bin/bash
# Description: Comprehensive search for usage of GHCRTS variable in shell scripts

# Search for direct usage
rg --type sh 'GHCRTS' .

# Search for exported usage
rg --type sh 'export GHCRTS' .

# Search for usage within strings or other contexts
rg --type sh '"GHCRTS"' .

Length of output: 132

🧰 Tools
🪛 Shellcheck

[warning] 16-16: GHCRTS appears unused. Verify use (or export if used externally).

(SC2034)

contracts/libraries/WithdrawalBatchesQueue.sol (1)

18-27: Approve the relocation of the Status enum with a note on potential impact.

The relocation of the Status enum inside the WithdrawalsBatchesQueue library improves encapsulation and reduces global namespace pollution. This change is syntactically correct and aligns with best practices for library design in Solidity.

However, this is a breaking change if the Status enum was previously used outside this library. Ensure that all references to this enum throughout the codebase have been updated accordingly.

To verify the impact of this change, run the following script:

✅ Verification successful

Verified: No external issues found with the relocation of the Status enum.

The Status enum has been successfully relocated inside the WithdrawalsBatchesQueue library. All references in the codebase, including those in test/kontrol/StorageSetup.sol and contracts/libraries/Proposals.sol, correctly utilize the enum through the library without introducing any conflicts or breaking changes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any external usage of the Status enum outside the WithdrawalBatchesQueue library

# Test: Search for Status enum usage outside the WithdrawalBatchesQueue library
rg --type solidity -g '!WithdrawalBatchesQueue.sol' 'enum\s+Status|WithdrawalsBatchesQueue\.Status'

# Note: If this search returns results, it indicates that the Status enum is being used elsewhere 
# in the codebase and those occurrences need to be updated.

Length of output: 134


Script:

#!/bin/bash
# Description: Check for any external usage of the Status enum outside the WithdrawalBatchesQueue library

# Test: Search for Status enum usage in .sol files excluding WithdrawalBatchesQueue.sol
rg -g '*.sol' -g '!WithdrawalBatchesQueue.sol' 'enum\s+Status|WithdrawalsBatchesQueue\.Status'

Length of output: 390

test/kontrol/scripts/common.sh (2)

35-37: LGTM: Improved clarity in comment

The updated comment provides clearer context about the location of the foundry.toml file, which is helpful for users and developers.


Line range hint 7-22: LGTM: Improved usage instructions

The updates to the usage_run_kontrol function significantly improve the clarity of the usage instructions. The refined descriptions for execution modes, particularly the recommendation for the "local" mode, provide valuable guidance to users. This change will help users make more informed decisions about which mode to use, potentially leading to better reproducibility of test results.

contracts/model/EmergencyProtectedTimelockModel.sol (2)

127-133: LGTM. Efficiency improvement in cancelAllNonExecutedProposals.

The addition of the if (nextProposalId > 0) check before the loop is a good optimization. It prevents unnecessary iterations when there are no proposals, improving gas efficiency and avoiding potential issues that could arise from iterating over an empty set of proposals.


Line range hint 1-233: Summary: Minor improvements with no functional changes.

The changes in this contract are minimal and beneficial:

  1. The contract has been renamed to better reflect its role as a model.
  2. An efficiency improvement has been added to the cancelAllNonExecutedProposals function.

These changes do not alter the core functionality of the contract and do not introduce any security vulnerabilities or logical errors. The contract's behavior remains consistent with its previous version, with slight improvements in clarity and efficiency.

test/kontrol/KontrolTest.sol (1)

58-62: Logic for overflow assumption is correct.

The _assumeNoOverflow function correctly uses unchecked arithmetic to assume that augend + addend does not overflow. The use of vm.assume with the condition augend < augend + addend ensures that the sum does not wrap around, which is appropriate.

test/kontrol/EscrowInvariants.sol (1)

47-51: Verify the correctness of the user invariant check

In the escrowUserInvariants function, the invariant ensures that a user's locked shares do not exceed the total locked shares:

_establish(
    mode,
    escrow.getVetoerState(user).stETHLockedShares <= escrow.getLockedAssetsTotals().stETHLockedShares
);

While this check seems logical, please verify that the aggregation of all users' stETHLockedShares correctly accounts for the total stETHLockedShares, and that there are no edge cases where this inequality might not hold due to rounding errors or synchronization issues.

To automate this verification, you can run the following script to ensure that the sum of all users' stETHLockedShares does not exceed totals.stETHLockedShares:

Please adjust the script as necessary to fit the actual structure of your codebase and data sources.

test/kontrol/DualGovernanceSetUp.sol (1)

28-28: Verify if setUp() function should be marked with override

Since DualGovernanceSetUp inherits from StorageSetup, if StorageSetup defines a setUp() function, the setUp() function here should be marked with the override keyword to correctly override the base function.

Run the following script to verify if StorageSetup contains a setUp() function:

contracts/model/StETHModel.sol (1)

150-153: Re-evaluate the restriction on transferring shares to the contract address

In the _transferShares function, there is a requirement that prevents transferring shares to the contract itself:

require(_recipient != address(this), "TRANSFER_TO_STETH_CONTRACT");

Determine if this restriction is necessary. In some ERC20 implementations, allowing transfers to the contract address is acceptable and can be useful. If there's no specific reason to prevent this, consider removing this restriction.

If you decide to remove it, modify the code as follows:

-require(_recipient != address(this), "TRANSFER_TO_STETH_CONTRACT");
test/kontrol/EscrowAccounting.t.sol (1)

19-25: Contract Initialization Appears Correct

The EscrowAccountingTest contract is properly declared, extending EscrowInvariants, and the state variables are appropriately defined.

test/kontrol/EscrowOperations.t.sol (1)

28-47: Function 'testCannotUnlockBeforeMinLockTime' is correctly implemented

The test function successfully verifies that unlocking stETH before the minimum lock time has elapsed reverts as expected.

test/kontrol/ActivateNextState.t.sol (1)

16-80: Ensure proper casting and type safety when using address(this)

In the activateNextState function, address(this) is cast to DualGovernance. Ensure that this contract correctly implements or simulates the DualGovernance interface to avoid runtime errors due to incorrect type casting.

To verify that ActivateNextStateMock is compatible with DualGovernance, check the inheritance hierarchy:

contracts/model/EscrowModel.sol (2)

185-202: Ensure proper handling of Ether in the contract

Given that the contract primarily deals with stETH tokens, and considering that stEth is an ERC20 token representing staked Ether, the contract should ensure a mechanism to handle conversions between stETH and ETH if it intends to transfer ETH during withdrawals. Without such a mechanism, the withdraw() function may fail or behave unexpectedly.

Would you like assistance in designing a mechanism to handle stETH to ETH conversion for withdrawals?


185-202: ⚠️ Potential issue

Potential mismatch between stETH holdings and ETH balance for withdrawals

In the withdraw() function, the contract attempts to transfer ETH to the user based on their staked shares:

uint256 totalEth = address(this).balance; // Total ETH held by contract
uint256 amount = stEth.getPooledEthByShares(stakedShares);
require(totalEth >= amount, "Not enough balance.");

shares[msg.sender] = 0;

// Transfer ETH equivalent
payable(msg.sender).transfer(amount);

However, the contract holds stETH, not ETH. Unless there is an internal mechanism that swaps stETH for ETH and ensures the contract has sufficient ETH balance, this withdrawal may fail due to insufficient ETH in the contract.

Run the following script to verify if the contract receives ETH or swaps stETH to ETH:

test/kontrol/lido-lemmas.k (8)

4-4: Ensure the use of the [symbolic] attribute is appropriate

The addition of the [symbolic] attribute to the LIDO-LEMMAS module at line 4 changes its operational context to work with symbolic execution. Please verify that this change aligns with the intended use of the module and that all dependent modules and specifications are compatible with this alteration.


14-14: Extension of StepSort syntax to include Map and Set

Adding Map and Set to the StepSort syntax at line 14 extends the types that can be processed by the module. This change seems appropriate if mappings and sets are now being handled within the lemmas. Ensure that all usages of StepSort are updated accordingly.


23-26: Validation of the arithmetic rule involving division and multiplication

The rule at lines 23-26 correctly transforms C <=Int A *Int B into C /Int A <=Int B under the given conditions. The requires clauses ensure non-negative values and proper divisibility, making the simplification valid.


28-30: Correct simplification of equality between positive and negative integers

The rule at lines 28-30 asserts that A ==Int B is false when A >= 0 and B < 0. This is logically sound, as a non-negative integer cannot equal a negative integer, and helps in simplifying expressions under these conditions.


32-33: Simplification of inequality involving subtraction

The rule at lines 32-33 simplifies 0 <=Int A -Int B to B <=Int A. This transformation is valid and serves to streamline inequalities within the symbolic reasoning.


35-38: Verify the complex arithmetic simplification for correctness

The rule at lines 35-38 introduces a complex simplification involving integer division and multiplication with specific constraints on A, D, and C. Given the complexity, please verify that this transformation accurately preserves the intended arithmetic relationships and does not introduce errors.


40-43: Validation of byte array comparison rule

The [asWord-lt-concat-left] rule at lines 40-43 transforms a comparison of concatenated byte arrays into a comparison involving only the left byte array and adjusted integer values. This seems correct under the specified requires clause and enhances the efficiency of symbolic comparisons.


121-125: Ensure intentional multiple updates to the same map key

In the claim [storage-simplification] starting at line 119, the Map STORAGE0 is updated multiple times at lines 121, 123, and 125 with the key 5. This results in the previous values being overwritten. Please confirm that this is intentional and that the overwriting does not affect the lemma's correctness.

test/kontrol/EscrowLockUnlock.t.sol (4)

25-28: Ensure vm and kevm are properly initialized.

The code uses vm.assume with address(vm) and address(kevm). Verify that both vm and kevm are correctly initialized and available in the testing context to avoid runtime issues.


223-225: Verify the behavior of the ActivateNextStateMock contract.

When mocking the activateNextState function, ensure that the mock accurately represents the desired behavior for the test. This verification helps prevent misleading test results.


162-164: Check the assumption on stEth.balanceOf(sender).

The assumption stEth.balanceOf(sender) < ethUpperBound depends on ethUpperBound. Verify that ethUpperBound is set appropriately to avoid invalid test scenarios.


198-201: Validate time-based assumptions for unlocking stETH.

The test assumes that the current time is greater than the last locked time plus the minimum lock time (Timestamps.now() > addTo(config.SIGNALLING_ESCROW_MIN_LOCK_TIME(), pre.userLastLockedTime)). Ensure that this condition is met in the test environment to prevent incorrect test failures.

contracts/model/DualGovernanceModel.sol (5)

90-90: Verify tuple unpacking in proposal retrieval

The tuple unpacking in the line:

(,, uint256 submissionTime,,) = emergencyProtectedTimelock.proposals(proposalId);

Ensure that the syntax is correct and that you're retrieving the intended value. Unused variables are ignored using commas, but verify that the positions align with the returned values from the proposals function.

Check the proposals function signature to confirm the order of returned values.


298-298: Making fromRageQuit function public may introduce security risks

Changing the fromRageQuit function from private to public exposes it to external calls. This could allow unauthorized state transitions if not properly secured.

Confirm that this change is intentional and that adequate access control is in place to prevent misuse.


25-27: Check compatibility with updated model classes

The state variables have been updated to use the new model classes:

  • EmergencyProtectedTimelockModel for emergencyProtectedTimelock
  • EscrowModel for signallingEscrow and rageQuitEscrow

Please verify that all interactions with these variables are compatible with the new model classes and that any changes in their interfaces are handled appropriately.

Run the following script to review usage of these variables:

#!/bin/bash
# Description: Find all usages of the updated variables
rg --type solidity "(emergencyProtectedTimelock|signallingEscrow|rageQuitEscrow)" -A 3 -B 1

16-16: Update all references to the contract name

The contract has been renamed from DualGovernance to DualGovernanceModel. Ensure that all references to the old contract name are updated throughout the codebase, including deployment scripts and documentation.

Run the following script to find any remaining references to the old contract name:

#!/bin/bash
# Description: Find all occurrences of "DualGovernance" in Solidity files
rg --type solidity "DualGovernance\b" --files-with-matches

6-7: Ensure the new model contracts are properly integrated

The imports have been updated to use EmergencyProtectedTimelockModel and EscrowModel. Please verify that these new contracts are correctly implemented and that any differences in their interfaces are accounted for in this contract.

Run the following script to check for any mismatches in function signatures or properties used from the new contracts:

contracts/libraries/DualGovernanceState.sol (4)

5-5: Import of Math Library is Appropriate

The addition of import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; is necessary for utilizing Math.max in timestamp calculations.


301-301: Verify Inclusion of Threshold Values in Comparisons

The comparison operators in _isFirstSealRageQuitSupportCrossed and _isSecondSealRageQuitSupportCrossed have changed from > to >=. This adjustment means that the thresholds firstSealRageQuitSupport and secondSealRageQuitSupport are now inclusive. Please confirm that this change aligns with the intended governance logic and that it correctly handles edge cases where rageQuitSupport equals the threshold values.

Also applies to: 308-308


331-341: Review Logic in Veto Signalling Reactivation Duration Calculation

The _isVetoSignallingReactivationDurationPassed function has been refactored to use Math.max between vetoSignallingActivationTime and vetoSignallingReactivationTime. Ensure that this modification accurately reflects the intended logic for determining when the veto signalling reactivation duration has passed, particularly in scenarios where reactivation time may affect state transitions.


395-404: ⚠️ Potential issue

Prevent Potential Division by Zero in Dynamic Timelock Calculation

In the _calcDynamicTimelockDuration function, there is a division operation:

(secondSealRageQuitSupport - firstSealRageQuitSupport)

To avoid a division by zero error, ensure that secondSealRageQuitSupport is always greater than firstSealRageQuitSupport. Please verify that the configuration enforces this condition.

test/kontrol/VetoSignalling.t.sol (2)

279-279: ⚠️ Potential issue

Remove unreachable code after return statement.

At line 279, vm.assume(currentState == State.VetoSignalling || currentState == State.VetoSignallingDeactivation); appears after a return statement at line 277. This code is unreachable and should be removed to improve code clarity.

Apply this diff to remove unreachable code:

     }
     return;
-    vm.assume(currentState == State.VetoSignalling || currentState == State.VetoSignallingDeactivation);
 }

Likely invalid or redundant comment.


97-98: Ensure safe casting when wrapping timestamps.

In line 98, Math.max returns a uint256, which is cast to uint40 before wrapping into a Timestamp. Since Timestamp values are uint40, ensure that the casting does not result in overflow. Although inputs are uint40, explicit checks can prevent unexpected issues.

Run the following script to verify that all unwrapped Timestamp values fit within uint40:

✅ Verification successful

Safe casting verified for Timestamp values.

All Timestamp.unwrap usages return uint40 values, ensuring that casting to uint40 does not cause overflow.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all Timestamp unwraps result in uint40 values.

# Test: Search for all unwrapping of Timestamps.
rg --type solidity 'Timestamp.unwrap\('

# Expected: All usages should involve values within the uint40 range.

Length of output: 74


Script:

#!/bin/bash
# Description: Verify that all Timestamp unwraps result in uint40 values by searching .sol files.

# Find all Solidity files and search for 'Timestamp.unwrap('
fd --extension sol --type file | xargs rg 'Timestamp.unwrap\('

Length of output: 1826


Script:

#!/bin/bash
# Description: Confirm that the Timestamp type is defined as uint40.

# Search for the definition of Timestamp in Solidity files
rg --files-with-matches 'type Timestamp' --type sol | xargs rg 'type Timestamp'

Length of output: 165

Comment on lines +12 to +13
function testVetoCooldownDuration() external {
vm.assume(dualGovernance.getCurrentState() == State.VetoCooldown);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider using vm.mockCall instead of vm.assume.

Using vm.assume doesn't guarantee that the initial state will be VetoCooldown. Consider using vm.mockCall or a similar method to explicitly set the initial state to VetoCooldown. This will ensure the test always starts in the correct state.

Comment on lines +14 to +21
Timestamp timeEnteredAt = Timestamp.wrap(_getEnteredAt(dualGovernance));
Timestamp maxCooldownDuration = addTo(config.VETO_COOLDOWN_DURATION(), timeEnteredAt);

dualGovernance.activateNextState();

bool stillInVetoCooldown = (dualGovernance.getCurrentState() == State.VetoCooldown);
bool durationHasElapsed = (Timestamps.now() > maxCooldownDuration);
assert(stillInVetoCooldown != durationHasElapsed);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add more specific assertions for better test coverage.

While the current assertion checks the relationship between the state and time, consider adding more specific assertions to validate:

  1. The initial state is indeed VetoCooldown.
  2. The maxCooldownDuration is calculated correctly.
  3. The state transition occurs at the expected time.

This will provide more comprehensive test coverage and make debugging easier if the test fails.

@@ -26,7 +26,7 @@ struct Proposal {

// This contract manages the timelocking of proposals with emergency intervention capabilities.
// It provides controls for entering and managing emergency states as well as executing proposals under normal and emergency conditions.
contract EmergencyProtectedTimelock {
contract EmergencyProtectedTimelockModel {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Incomplete contract renaming detected.

References to EmergencyProtectedTimelock still exist in the following files:

  • test/utils/scenario-test-blueprint.sol
  • test/unit/EmergencyProtectedTimelock.t.sol
  • test/kontrol/StorageSetup.sol
  • test/kontrol/ProposalOperationsSetup.sol
  • test/kontrol/ProposalOperations.t.sol
  • test/kontrol/EscrowLockUnlock.t.sol
  • test/kontrol/EscrowInvariants.sol
  • test/kontrol/EscrowAccounting.t.sol
  • test/kontrol/DualGovernanceSetUp.sol
  • contracts/ResealManager.sol
  • contracts/EmergencyProtectedTimelock.sol
  • contracts/committees/EmergencyExecutionCommittee.sol
  • contracts/committees/EmergencyActivationCommittee.sol

Please update these references to EmergencyProtectedTimelockModel to ensure consistency across the codebase.

🔗 Analysis chain

LGTM. Verify contract name usage across the codebase.

The contract renaming from EmergencyProtectedTimelock to EmergencyProtectedTimelockModel is appropriate as it better reflects the contract's role as a model. However, ensure that all references to this contract in other parts of the codebase have been updated accordingly.

Run the following script to check for any remaining references to the old contract name:


Adjust the search commands to target .sol files and re-verify contract references.

The previous search command did not recognize the solidity file type. Please update the search to target .sol files and rerun the verification scripts to ensure all references to EmergencyProtectedTimelockModel are correctly updated.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for any remaining references to the old contract name

# Test: Search for the old contract name. Expect: No results.
rg --type solidity "EmergencyProtectedTimelock"

# Test: Search for the new contract name. Expect: At least one result in this file.
rg --type solidity "EmergencyProtectedTimelockModel"

Length of output: 166


Script:

#!/bin/bash
# Description: Search for any remaining references to the old contract name using the correct file extension

# Test: Search for the old contract name. Expect: No results.
rg -g '*.sol' "EmergencyProtectedTimelock"

# Test: Search for the new contract name. Expect: At least one result in this file.
rg -g '*.sol' "EmergencyProtectedTimelockModel"

Length of output: 9345

Comment on lines +12 to +13
uint256 constant timeUpperBound = 2 ** 35;

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add explicit visibility to constant declaration.

Similarly, the constant timeUpperBound lacks an explicit visibility modifier. Adding it enhances clarity.

-uint256 constant timeUpperBound = 2 ** 35;
+uint256 constant internal timeUpperBound = 2 ** 35;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
uint256 constant timeUpperBound = 2 ** 35;
uint256 constant internal timeUpperBound = 2 ** 35;

Comment on lines +9 to +10
uint256 constant ethMaxWidth = 96;
uint256 constant ethUpperBound = 2 ** ethMaxWidth;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add explicit visibility to constant declarations.

The constants ethMaxWidth and ethUpperBound do not have explicit visibility specified. In Solidity, it's good practice to declare visibility for state variables and constants to improve code readability and maintainability.

Consider specifying the visibility as internal or public:

-uint256 constant ethMaxWidth = 96;
-uint256 constant ethUpperBound = 2 ** ethMaxWidth;
+uint256 constant internal ethMaxWidth = 96;
+uint256 constant internal ethUpperBound = 2 ** ethMaxWidth;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
uint256 constant ethMaxWidth = 96;
uint256 constant ethUpperBound = 2 ** ethMaxWidth;
uint256 constant internal ethMaxWidth = 96;
uint256 constant internal ethUpperBound = 2 ** ethMaxWidth;

Comment on lines +59 to +61
function _getCurrentState(DualGovernance _dualGovernance) internal view returns (uint8) {
return uint8(_loadUInt256(address(_dualGovernance), 5));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider renaming overloaded _getCurrentState functions for clarity

The _getCurrentState function is defined twice with different parameters:

  • Lines 59-61: function _getCurrentState(DualGovernance _dualGovernance) internal view returns (uint8)
  • Lines 172-174: function _getCurrentState(IEscrow _escrow) internal view returns (uint8)

While Solidity allows function overloading based on parameter types, having functions with the same name but different parameters can lead to confusion and potential misuse. Renaming one of the functions to reflect its specific context can improve code readability and maintainability.

Also applies to: 172-174

Comment on lines +90 to +105
uint8 currentState = uint8(kevm.freshUInt(1));
vm.assume(currentState <= 4);
uint40 enteredAt = uint40(kevm.freshUInt(5));
vm.assume(enteredAt <= block.timestamp);
vm.assume(enteredAt < timeUpperBound);
uint40 vetoSignallingActivationTime = uint40(kevm.freshUInt(5));
vm.assume(vetoSignallingActivationTime <= block.timestamp);
vm.assume(vetoSignallingActivationTime < timeUpperBound);
bytes memory slot5Abi = abi.encodePacked(
uint8(0),
uint160(address(_signallingEscrow)),
uint40(vetoSignallingActivationTime),
uint40(enteredAt),
uint8(currentState)
);
bytes32 slot5;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Define constants or enums for state values and storage slot numbers

In the dualGovernanceStorageSetup function, magic numbers are used for currentState and storage slot numbers:

  • currentState is assumed to be <= 4 (lines 90-91).
  • Storage slots 5 and 6 are used directly (lines 90 and 110).

Consider defining an enum for currentState and constants for storage slot numbers to enhance readability and reduce the risk of errors.

Example:

enum GovernanceState { State0, State1, State2, State3, State4 }
uint256 constant SLOT_CURRENT_STATE = 5;
uint256 constant SLOT_ADDITIONAL_DATA = 6;

Comment on lines +315 to +316
// FIXME: This branching is done to avoid the fresh existential generation bug
if (_currentState == EscrowState.RageQuitEscrow) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Address the FIXME comment and clarify the workaround

There's a FIXME comment indicating that branching is done to avoid the "fresh existential generation bug":

// FIXME: This branching is done to avoid the fresh existential generation bug
if (_currentState == EscrowState.RageQuitEscrow) {
    // ...
}

It's important to either resolve this issue or provide additional context about the workaround. This will help maintain code clarity and assist future developers in understanding the necessity of this branching.

Would you like assistance in addressing this FIXME comment or providing a more detailed explanation of the workaround? I can help refactor the code or open a GitHub issue to track this task.

Comment on lines +332 to +333
// FIXME: This branching is done to avoid the fresh existential generation bug
if (_currentState == EscrowState.RageQuitEscrow) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Address the FIXME comment and clarify the workaround

Similar to the previous comment, there's a FIXME comment in the escrowStorageSetup function:

// FIXME: This branching is done to avoid the fresh existential generation bug
if (_currentState == EscrowState.RageQuitEscrow) {
    // ...
}

Ensuring that this issue is resolved or adequately documented will improve code maintainability and reduce potential confusion.

Would you like assistance in resolving this FIXME or enhancing the documentation around this workaround?

Comment on lines +173 to +174
return uint8(_loadUInt256(address(_escrow), 0));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use descriptive constants for storage slot indices

In functions accessing storage slots directly, such as _getCurrentState and _getBatchesQueueStatus, hardcoded storage slot numbers are used:

  • _getCurrentState uses slot 0 (line 173).
  • _getBatchesQueueStatus uses slot 5 (line 201).

Defining descriptive constants for these storage slot indices can improve code readability and reduce the likelihood of errors when modifying storage structures.

Example:

uint256 constant SLOT_ESCROW_CURRENT_STATE = 0;
uint256 constant SLOT_BATCHES_QUEUE_STATUS = 5;

// Usage:
return uint8(_loadUInt256(address(_escrow), SLOT_ESCROW_CURRENT_STATE));

Also applies to: 201-202

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants