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

add governor role for access to setters for term strategy parameters #75

Merged
merged 2 commits into from
Oct 29, 2024

Conversation

aazhou1
Copy link

@aazhou1 aazhou1 commented Oct 26, 2024

Summary by CodeRabbit

  • New Features

    • Introduced a new input variable GOVERNOR_ROLE_ADDRESS for enhanced deployment capabilities on the Sepolia network.
    • Added role-based access control to the Strategy contract, improving security and management flexibility.
  • Bug Fixes

    • Updated error handling in tests to ensure clarity and precision in revert messages.
  • Documentation

    • Enhanced testing capabilities with new functions for role-based revert expectations and improved error reporting.
  • Chores

    • Adjusted various tests to align with the new governance structure, replacing management with governor.

@aazhou1 aazhou1 self-assigned this Oct 26, 2024
Copy link

coderabbitai bot commented Oct 26, 2024

Walkthrough

The pull request introduces modifications to several files, primarily focusing on the integration of a new input variable, GOVERNOR_ROLE_ADDRESS, into the GitHub Actions workflow for deploying a strategy on the Sepolia network. This variable is utilized in the deployment script and the Strategy contract, which has been updated to employ role-based access control via OpenZeppelin's AccessControl. The changes also include adjustments in test contracts to reflect the new governance structure, ensuring that the governor address replaces the management address in various function calls.

Changes

File Change Summary
.github/workflows/deploy-sepolia-strategy.yaml Added new input variable GOVERNOR_ROLE_ADDRESS to the environment variables section for deployment.
script/Strategy.s.sol Introduced governorRoleAddress variable and updated Strategy constructor to include this new parameter.
src/Strategy.sol Integrated AccessControl, replaced onlyManagement with onlyRole(GOVERNOR_ROLE) in multiple functions, added GOVERNOR_ROLE constant, and updated the constructor to accept _governorAddress.
src/test/TestUSDCIntegration.t.sol Replaced management address with governor in vm.startPrank() calls for privileged actions, simplified revert messages.
src/test/TestUSDCOffers.t.sol Updated vm.startPrank() to use governor instead of management, modified error handling for auction offer submissions.
src/test/TestUSDCSellRepoToken.t.sol Changed vm.startPrank() and vm.prank calls to use governor, simplified revert messages.
src/test/TestUSDCSubmitOffer.t.sol Adjusted setUp to use governor in vm.startPrank(), updated error handling for submitAuctionOffer.
src/test/utils/ExtendedTest.sol Added expectRoleRevert function for role-based revert expectations and overloaded assertApproxEq for custom error messages.
src/test/utils/Setup.sol Introduced public address variable governor, modified setUpStrategy to include governor in Strategy instantiation, and updated vm.prank to use governor.

Possibly related PRs

Suggested reviewers

  • 0xddong

🐰 "In the meadow, changes bloom,
A governor's role now finds its room.
With strategies set and tokens aligned,
Our contracts grow, robust and refined.
Hops of progress, leaps of cheer,
In code we trust, our path is clear!" 🐇


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: 3

🧹 Outside diff range and nitpick comments (4)
script/Strategy.s.sol (1)

40-41: Fix typo in log message & LGTM on constructor changes.

The constructor parameter addition is correct, but there's a typo in the log message after this block ("strateghy" instead of "strategy").

-        console.log("deployed strateghy contract to");
+        console.log("deployed strategy contract to");
src/test/utils/Setup.sol (1)

122-123: Consider improving parameter formatting for better readability.

While the parameter additions are correct, the formatting could be improved to maintain consistent indentation with other parameters.

Consider this formatting:

    new Strategy(
        address(asset), 
        "Tokenized Strategy", 
        address(mockYearnVault), 
        address(discountRateAdapter),
-                    address(termVaultEventEmitter),
-                    governor
+        address(termVaultEventEmitter),
+        governor
    )
src/test/TestUSDCOffers.t.sol (1)

Line range hint 1-444: Consider adding additional test cases for comprehensive coverage

While the current test coverage is good, consider adding these test cases to ensure robust validation of the governor role:

  1. Attempt to call setter functions with non-governor address
  2. Test parameter boundary conditions with governor role
  3. Verify parameter persistence after setting with governor role

Would you like me to help generate these additional test cases?

src/Strategy.sol (1)

Line range hint 467-467: Inconsistent use of access control modifiers

The functions submitAuctionOffer and deleteAuctionOffers still use onlyManagement for access control, whereas other functions have transitioned to onlyRole(GOVERNOR_ROLE). For consistency and to centralize permission management, consider replacing onlyManagement with onlyRole(GOVERNOR_ROLE).

Apply the following diff to update access control:

-function submitAuctionOffer(
+function submitAuctionOffer(
     ITermAuction termAuction,
     address repoToken,
     bytes32 idHash,
     bytes32 offerPriceHash,
     uint256 purchaseTokenAmount
-)
+)
     external
     whenNotPaused
     nonReentrant
     notBlacklisted(repoToken)
-    onlyManagement
+    onlyRole(GOVERNOR_ROLE)
     returns (bytes32[] memory offerIds)
 {
     require(purchaseTokenAmount > 0, "Purchase token amount must be greater than zero");
     // Function body...
 }

-function deleteAuctionOffers(
+function deleteAuctionOffers(
     address termAuction,
     bytes32[] calldata offerIds
-)
+)
     external
-    onlyManagement
+    onlyRole(GOVERNOR_ROLE)
 {
     // Function body...
 }

Also applies to: 595-595

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 0fc52e4 and 5b16ede.

📒 Files selected for processing (9)
  • .github/workflows/deploy-sepolia-strategy.yaml (1 hunks)
  • script/Strategy.s.sol (2 hunks)
  • src/Strategy.sol (14 hunks)
  • src/test/TestUSDCIntegration.t.sol (6 hunks)
  • src/test/TestUSDCOffers.t.sol (3 hunks)
  • src/test/TestUSDCSellRepoToken.t.sol (11 hunks)
  • src/test/TestUSDCSubmitOffer.t.sol (2 hunks)
  • src/test/utils/ExtendedTest.sol (1 hunks)
  • src/test/utils/Setup.sol (4 hunks)
🔇 Additional comments (38)
.github/workflows/deploy-sepolia-strategy.yaml (1)

67-67: LGTM! Verify environment configuration.

The addition of GOVERNOR_ROLE_ADDRESS follows the established pattern for role-based access control and is appropriately configured using repository variables.

Let's verify the environment configuration:

✅ Verification successful

✓ GOVERNOR_ROLE configuration is properly integrated

The GOVERNOR_ROLE is correctly implemented and consistently used across the codebase:

  • Defined as a constant in src/Strategy.sol
  • Used with onlyRole modifier for all governor-restricted functions
  • Properly granted during contract initialization
  • Referenced in deployment script Strategy.s.sol using the environment variable
  • Workflow variable aligns with the implementation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that GOVERNOR_ROLE_ADDRESS is properly configured in the Sepolia environment
# and follows the same pattern as other role addresses.

# Test: Check if the variable is referenced consistently across deployment-related files
rg -A 2 "GOVERNOR_ROLE|governor" --type yaml --type sol

Length of output: 85


Script:

#!/bin/bash
# Let's try a different approach to verify the GOVERNOR_ROLE usage:

# 1. Check workflow files for GOVERNOR_ROLE
rg "GOVERNOR_ROLE" .github/workflows/

# 2. Find all Solidity files that might contain governor role references
fd "\.sol$"

# 3. Check content of found Solidity files for governor-related code
rg "governor|GOVERNOR" --type-add 'sol:*.sol' -t sol

Length of output: 5362

src/test/utils/ExtendedTest.sol (1)

86-86: LGTM: New overload of assertApproxEq with error message.

The addition of a custom error message parameter enhances the test failure output without changing the core functionality.

script/Strategy.s.sol (2)

Line range hint 48-73: Verify permission requirements for test mode configuration.

The test mode configuration calls several setter functions that might now require governor role permissions. Ensure that these calls will work with the new access control system.

Let's check the Strategy contract's permission requirements:

#!/bin/bash
# Check permission requirements for setter functions in Strategy contract
ast-grep --pattern 'function set$$$($$$) $$$onlyRole(GOVERNOR_ROLE)$$$'

25-25: LGTM! Verify environment variable setup in CI/CD.

The governor role address is properly retrieved using vm.envAddress.

Let's verify the environment variable is properly set in the deployment workflow:

✅ Verification successful

Environment variable GOVERNOR_ROLE_ADDRESS is properly configured

The GOVERNOR_ROLE_ADDRESS is correctly set up in the deployment workflow:

  • It's defined as ${{ vars.GOVERNOR_ROLE_ADDRESS }} in the strategy deployment workflow
  • It's used as a required parameter in the Strategy constructor
  • The variable is stored in GitHub repository variables (vars) which is the appropriate place for non-sensitive configuration
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if GOVERNOR_ROLE_ADDRESS is properly configured in deployment workflows
rg -l "GOVERNOR_ROLE_ADDRESS:" .github/workflows/

Length of output: 73


Script:

#!/bin/bash
# Let's check for workflow files and their content
fd -e yml -e yaml . .github/workflows/ -x cat {}

# Also check if there are any environment files that might contain this variable
fd -g '*.env*' . -x cat {}

# Check the deployment script itself to understand the context better
cat script/Strategy.s.sol

Length of output: 10323

src/test/utils/Setup.sol (3)

44-44: LGTM: Governor role declaration follows established patterns.

The new governor role is properly declared and initialized, maintaining consistency with other role address declarations in the test setup.


108-108: LGTM: Governor address properly labeled for test traces.

The governor address is appropriately labeled, maintaining consistency with other role labels and improving test trace readability.


141-142: Verify access control consistency with Strategy contract.

The change from management to governor for setting the term controller aligns with the PR objective. However, we should verify this matches the Strategy contract's access control implementation.

✅ Verification successful

Access control verification successful - setTermController requires GOVERNOR_ROLE

The change from management to governor in the test setup is consistent with the Strategy contract's implementation. The setTermController function in Strategy.sol explicitly requires GOVERNOR_ROLE through the onlyRole modifier, confirming that only accounts with governor privileges can set the term controller.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the Strategy contract uses GOVERNOR_ROLE for setTermController

# Test: Search for setTermController function definition
ast-grep --pattern 'function setTermController($$$) {
  $$$
}'

# Test: Search for GOVERNOR_ROLE usage in access control
rg -A 2 'GOVERNOR_ROLE'

Length of output: 3200

src/test/TestUSDCSubmitOffer.t.sol (2)

Line range hint 36-42: LGTM! Clear separation of roles implemented.

The changes correctly implement role-based access control by having the governor set critical strategy parameters during setup, while maintaining management's operational role for offer submissions.


96-97: LGTM! Verify role-based access control implementation.

The change correctly uses the governor role for setting concentration limits while preserving management's ability to submit offers.

Let's verify the complete role-based access control implementation:

✅ Verification successful

Role-based access control implementation verified correctly

The verification confirms proper role separation:

  • Governor role is consistently used for all parameter setters (setTermController, setDiscountRateAdapter, setTimeToMaturityThreshold, etc.) and admin functions (pause/unpause)
  • Management role is properly restricted to operational functions (submitAuctionOffer, deleteAuctionOffers)
  • Access control is enforced through onlyRole(GOVERNOR_ROLE) and onlyManagement modifiers
  • No instances found where management can access governor functions or vice versa
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent role-based access control implementation
# Expected: governor for parameter setters, management for operations

# Check for any remaining management calls to setter functions
rg -A 2 "management.*set[A-Z]" 

# Check for any governor calls to operational functions
rg -A 2 "governor.*(submit|delete|auction)"

# Check for proper role separation in tests
ast-grep --pattern 'function test$_() {
  $$$
  vm.prank(management);
  $$$
}'

Length of output: 159


Script:

#!/bin/bash
# Let's try a more comprehensive search for role-based patterns

# Search for prank calls with governor role
rg -A 2 "prank.*governor"

# Search for prank calls with management role
rg -A 2 "prank.*management"

# Search for setters to understand access control
rg -A 2 "function set[A-Z][a-zA-Z]*\("

# Search for onlyGovernor modifier usage
rg -A 2 "onlyGovernor"

# Search for onlyManagement modifier usage
rg -A 2 "onlyManagement"

Length of output: 14991

src/test/TestUSDCIntegration.t.sol (5)

Line range hint 64-70: LGTM: Proper governor role implementation for parameter setters

The change correctly implements the governor role for setting strategy parameters, with proper access control wrapping.


251-254: LGTM: Consistent governor role implementation

The changes maintain consistency with the governor role pattern established in the setup.


Line range hint 323-343: LGTM: Comprehensive pause functionality testing

The test cases properly verify both authorized (governor) and unauthorized access for pause/unpause functionality.


357-366: LGTM: Well-structured discount rate adapter tests

The test cases thoroughly verify the discount rate adapter functionality with proper authorization checks and error handling.


306-312: Verify the expected revert message behavior

The test removes the specific revert message ("!management"). While this might be correct if using OpenZeppelin's AccessControl, it would be beneficial to verify that the actual revert message matches the expected AccessControl behavior.

✅ Verification successful

Removal of specific revert message is correct

The verification confirms that the contract uses OpenZeppelin's AccessControl with GOVERNOR_ROLE and the onlyRole modifier. The removal of the specific revert message "!management" is correct because:

  1. The function setRepoTokenBlacklist is protected by onlyRole(GOVERNOR_ROLE)
  2. AccessControl's onlyRole modifier handles the revert message automatically
  3. The test correctly verifies both unauthorized and authorized access scenarios
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for AccessControl usage in Strategy contract
ast-grep --pattern 'import {$_} from "@openzeppelin/contracts/access/AccessControl.sol"'

Length of output: 90


Script:

#!/bin/bash
# Let's try a broader search for AccessControl imports and inheritance
rg -l "AccessControl" 

# Also search for role-based access patterns
ast-grep --pattern 'bytes32 public constant $_ = keccak256'

# Check the actual implementation of setRepoTokenBlacklist
ast-grep --pattern 'function setRepoTokenBlacklist($$$) {
  $$$
}'

Length of output: 263


Script:

#!/bin/bash
# Let's examine the Strategy.sol file for the implementation details
rg -A 5 "setRepoTokenBlacklist" src/Strategy.sol

# Check for role definitions in Strategy.sol
rg "MANAGEMENT_ROLE|DEFAULT_ADMIN_ROLE" src/Strategy.sol

# Look at the actual contract definition to see access control inheritance
rg -A 3 "contract Strategy" src/Strategy.sol

Length of output: 686


Script:

#!/bin/bash
# Let's check for GOVERNOR_ROLE definition
rg "GOVERNOR_ROLE" src/Strategy.sol

# And check if there are any specific revert messages in BaseStrategy
rg -A 3 "contract BaseStrategy" src/BaseStrategy.sol

# Look for any custom errors related to governance
rg "error.*Governor" src/*.sol

Length of output: 1099

src/test/TestUSDCOffers.t.sol (3)

Line range hint 43-49: LGTM: Proper initialization of strategy parameters with governor role

The setup correctly implements the new access control mechanism by using the governor role to set strategy parameters.


91-98: LGTM: Clear separation of governor and management roles

The test case correctly demonstrates the separation of responsibilities:

  • Governor role for parameter configuration
  • Management role for operational tasks

137-144: LGTM: Consistent implementation of role-based access control

The test case maintains consistency with other tests in implementing the role-based access control pattern and proper error validation.

src/test/TestUSDCSellRepoToken.t.sol (6)

Line range hint 48-52: LGTM: Proper governor role usage in setUp.

The setup correctly uses the governor role to initialize strategy parameters.


80-83: LGTM: Proper governor role usage in test setup.

The test correctly uses the governor role to set collateral token parameters and maturity threshold.


469-480: LGTM: Proper governor role usage in validation tests.

The test correctly uses the governor role to set parameters for repo token validation tests.


493-494: LGTM: Proper governor role usage in maturity threshold test.

The test correctly uses the governor role to set the time to maturity threshold.


630-635: LGTM: Proper governor role usage in concentration limit test.

The test correctly verifies that:

  1. Non-governor accounts cannot modify the concentration limit
  2. Governor can successfully set the concentration limit

Line range hint 658-676: LGTM: Proper governor role usage in pause functionality test.

The test correctly verifies that:

  1. Non-governor accounts cannot pause/unpause the strategy
  2. Governor can successfully pause and unpause the strategy
  3. Paused state properly prevents deposits and repo token sales
src/Strategy.sol (15)

19-19: Importing AccessControl: Proper inclusion for role management

The addition of AccessControl import allows the contract to leverage role-based access control features, which is appropriate for managing permissions.


37-37: Inheriting AccessControl: Correct integration of access control

The contract now inherits from AccessControl, enabling role-based permission management throughout the contract.


51-51: Defining GOVERNOR_ROLE constant: Appropriate role setup

Defining GOVERNOR_ROLE as a constant using keccak256 ensures a unique identifier for the role, which is a best practice.


87-89: Updated access control to GOVERNOR_ROLE in pauseDeposit

The pauseDeposit function now correctly uses onlyRole(GOVERNOR_ROLE) for access control, ensuring only authorized users can invoke it.


95-97: Updated access control to GOVERNOR_ROLE in unpauseDeposit

The unpauseDeposit function now correctly uses onlyRole(GOVERNOR_ROLE), maintaining consistent access control.


103-105: Updated access control to GOVERNOR_ROLE in pauseStrategy

The pauseStrategy function now uses onlyRole(GOVERNOR_ROLE), aligning with the role-based access control system.


112-114: Updated access control to GOVERNOR_ROLE in unpauseStrategy

The unpauseStrategy function correctly uses onlyRole(GOVERNOR_ROLE) for access control.


Line range hint 124-130: Updated access control in setTermController

The setTermController function now requires onlyRole(GOVERNOR_ROLE), ensuring only the governor can change the term controller.


Line range hint 142-149: Updated access control in setDiscountRateAdapter

Access control is updated to onlyRole(GOVERNOR_ROLE) in setDiscountRateAdapter, which is appropriate.


Line range hint 158-164: Updated access control in setTimeToMaturityThreshold

The function now requires onlyRole(GOVERNOR_ROLE), maintaining consistent access control.


Line range hint 173-179: Updated access control in setRequiredReserveRatio

Using onlyRole(GOVERNOR_ROLE) in this function ensures only the governor can modify the required reserve ratio.


Line range hint 187-193: Updated access control in setRepoTokenConcentrationLimit

The function now correctly uses onlyRole(GOVERNOR_ROLE) for access control.


Line range hint 201-208: Updated access control in setDiscountRateMarkup

Requiring onlyRole(GOVERNOR_ROLE) in this function ensures that only authorized roles can change the discount rate markup.


216-222: Updated access control in setCollateralTokenParams

The function now uses onlyRole(GOVERNOR_ROLE) for access control, which is appropriate.


224-226: Added function setRepoTokenBlacklist with GOVERNOR_ROLE access control

The new function setRepoTokenBlacklist allows blacklisting of repo tokens and is appropriately protected by onlyRole(GOVERNOR_ROLE).

Comment on lines +87 to +95
function expectRoleRevert(bytes32 role) internal {
string memory revertMessage = string(abi.encodePacked(
"AccessControl: account ",
address(this),
" is missing role ",
role
));
vm.expectRevert(bytes(revertMessage));
}
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 making the caller address configurable.

The expectRoleRevert function assumes that address(this) is always the caller address in the revert message. This might not be flexible enough for testing scenarios where the unauthorized caller is a different address.

Consider this implementation:

-    function expectRoleRevert(bytes32 role) internal {
+    function expectRoleRevert(bytes32 role, address account) internal {
         string memory revertMessage = string(abi.encodePacked(
             "AccessControl: account ", 
-            address(this),
+            account,
             " is missing role ", 
             role
         ));
         vm.expectRevert(bytes(revertMessage));
     }
+
+    // Overload for backward compatibility and convenience when this contract is the caller
+    function expectRoleRevert(bytes32 role) internal {
+        expectRoleRevert(role, address(this));
+    }
📝 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
function expectRoleRevert(bytes32 role) internal {
string memory revertMessage = string(abi.encodePacked(
"AccessControl: account ",
address(this),
" is missing role ",
role
));
vm.expectRevert(bytes(revertMessage));
}
function expectRoleRevert(bytes32 role, address account) internal {
string memory revertMessage = string(abi.encodePacked(
"AccessControl: account ",
account,
" is missing role ",
role
));
vm.expectRevert(bytes(revertMessage));
}
// Overload for backward compatibility and convenience when this contract is the caller
function expectRoleRevert(bytes32 role) internal {
expectRoleRevert(role, address(this));
}

Comment on lines +409 to +446
vm.expectRevert();
termStrategy.setTermController(address(newController));

vm.expectRevert();
vm.prank(management);
vm.prank(governor);
termStrategy.setTermController(address(0));

address currentController = address(termStrategy.currTermController());
vm.prank(management);
vm.prank(governor);
termStrategy.setTermController(address(newController));
assertEq(address(termStrategy.currTermController()), address(newController));
assertEq(address(termStrategy.prevTermController()), currentController);

vm.expectRevert("!management");
vm.expectRevert();
termStrategy.setTimeToMaturityThreshold(12345);

vm.prank(management);
vm.prank(governor);
termStrategy.setTimeToMaturityThreshold(12345);
assertEq(termStrategy.timeToMaturityThreshold(), 12345);

vm.expectRevert("!management");
vm.expectRevert();
termStrategy.setRequiredReserveRatio(12345);

vm.prank(management);
vm.prank(governor);
termStrategy.setRequiredReserveRatio(12345);
assertEq(termStrategy.requiredReserveRatio(), 12345);

vm.expectRevert("!management");
vm.expectRevert();
termStrategy.setDiscountRateMarkup(12345);

vm.prank(management);
vm.prank(governor);
termStrategy.setDiscountRateMarkup(12345);
assertEq(termStrategy.discountRateMarkup(), 12345);

vm.expectRevert("!management");
vm.expectRevert();
termStrategy.setCollateralTokenParams(address(mockCollateral), 12345);

vm.prank(management);
vm.prank(governor);
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Events are properly emitted for parameter changes, but boundary tests are missing.

The code shows that all parameter changes emit events through TERM_VAULT_EVENT_EMITTER:

  • emitTermControllerUpdated for controller changes
  • emitTimeToMaturityThresholdUpdated for maturity threshold
  • emitRequiredReserveRatioUpdated for reserve ratio
  • emitDiscountRateMarkupUpdated for discount rate markup
  • emitMinCollateralRatioUpdated for collateral params

However, the tests should be extended to verify:

  • Maximum values for ratios (e.g., reserve ratio > 1e18)
  • Zero values for thresholds and markups
  • Negative impact scenarios (e.g., very low reserve ratio)
🔗 Analysis chain

Verify access control test coverage.

The governance parameter tests correctly verify that:

  1. Non-governor accounts cannot modify parameters (lines 409, 422, 429, 436, 443)
  2. Governor can successfully modify parameters
  3. Zero address validation for critical parameters (line 413)

However, consider adding tests for:

  • Parameter boundary values
  • Event emissions for parameter changes
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are any event emission tests for parameter changes
rg -A 2 "emit.*\b(TimeToMaturityThreshold|RequiredReserveRatio|DiscountRateMarkup|CollateralTokenParams)\b"

Length of output: 109


Script:

#!/bin/bash
# Check for event declarations in the contract
rg -A 2 "event.*\b(TimeToMaturityThreshold|RequiredReserveRatio|DiscountRateMarkup|CollateralTokenParams)\b"

# Check the contract implementation for event emissions
ast-grep --pattern 'emit $name($$$);'

# Get the contract interface/implementation
fd -e sol -x cat {} | grep -A 5 "function set.*\b(TimeToMaturityThreshold|RequiredReserveRatio|DiscountRateMarkup|CollateralTokenParams)\b"

Length of output: 294


Script:

#!/bin/bash
# Let's first find the contract file that contains these setter functions
fd -e sol | xargs grep -l "setTimeToMaturityThreshold\|setRequiredReserveRatio\|setDiscountRateMarkup\|setCollateralTokenParams"

# Then get the full content of the contract to analyze events and function implementations
fd "TermStrategy.sol" -t f -x cat {}

Length of output: 345


Script:

#!/bin/bash
# Let's check the Strategy.sol file since it appears to be the main contract
cat src/Strategy.sol

Length of output: 52813

@@ -1111,6 +1116,8 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard {
requiredReserveRatio = 0.2e18;
discountRateMarkup = 0.005e18;
repoTokenConcentrationLimit = 0.1e18;

_grantRole(GOVERNOR_ROLE, _governorAddress);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Missing assignment of DEFAULT_ADMIN_ROLE

Consider assigning the DEFAULT_ADMIN_ROLE to the governor address to enable future role management. Without an account holding DEFAULT_ADMIN_ROLE, it won't be possible to grant or revoke roles after deployment.

Apply this diff to the constructor to set the DEFAULT_ADMIN_ROLE:

 constructor(
     address _asset,
     string memory _name,
     address _yearnVault,
     address _discountRateAdapter,
     address _eventEmitter,
     address _governorAddress
 ) BaseStrategy(_asset, _name) {
     YEARN_VAULT = IERC4626(_yearnVault);
     TERM_VAULT_EVENT_EMITTER = ITermVaultEvents(_eventEmitter);
     PURCHASE_TOKEN_PRECISION = 10 ** ERC20(asset).decimals();
     discountRateAdapter = ITermDiscountRateAdapter(_discountRateAdapter);
     IERC20(_asset).safeApprove(_yearnVault, type(uint256).max);
     timeToMaturityThreshold = 45 days;
     requiredReserveRatio = 0.2e18;
     discountRateMarkup = 0.005e18;
     repoTokenConcentrationLimit = 0.1e18;

+    _grantRole(DEFAULT_ADMIN_ROLE, _governorAddress);
     _grantRole(GOVERNOR_ROLE, _governorAddress);
 }
📝 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
_grantRole(GOVERNOR_ROLE, _governorAddress);
constructor(
address _asset,
string memory _name,
address _yearnVault,
address _discountRateAdapter,
address _eventEmitter,
address _governorAddress
) BaseStrategy(_asset, _name) {
YEARN_VAULT = IERC4626(_yearnVault);
TERM_VAULT_EVENT_EMITTER = ITermVaultEvents(_eventEmitter);
PURCHASE_TOKEN_PRECISION = 10 ** ERC20(asset).decimals();
discountRateAdapter = ITermDiscountRateAdapter(_discountRateAdapter);
IERC20(_asset).safeApprove(_yearnVault, type(uint256).max);
timeToMaturityThreshold = 45 days;
requiredReserveRatio = 0.2e18;
discountRateMarkup = 0.005e18;
repoTokenConcentrationLimit = 0.1e18;
_grantRole(DEFAULT_ADMIN_ROLE, _governorAddress);
_grantRole(GOVERNOR_ROLE, _governorAddress);
}

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.

1 participant