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

feat: limit msg and payload size #376

Merged
merged 5 commits into from
Oct 4, 2024
Merged

Conversation

skosito
Copy link
Contributor

@skosito skosito commented Oct 4, 2024

limits payload/message len + revertOptions.revertMessage len < 512

questions:

  • is this too small?
  • should we make limit size configurable by admin so we can change it with setter?

Summary by CodeRabbit

  • New Features

    • Introduced constants to enforce maximum payload/message sizes in deposit and call functions for improved validation.
    • Added specific error messages for exceeding payload and message sizes.
  • Bug Fixes

    • Enhanced error handling to prevent operations with oversized payloads/messages.
  • Tests

    • Added multiple test cases to ensure proper error handling for oversized payloads/messages in various functions, including deposit and withdrawal scenarios.

Copy link
Contributor

coderabbitai bot commented Oct 4, 2024

Caution

Review failed

The pull request is closed.

📝 Walkthrough
📝 Walkthrough

Walkthrough

The pull request introduces several modifications to the GatewayEVM and GatewayZEVM contracts, focusing on payload and message size validations. A constant MAX_PAYLOAD_SIZE for GatewayEVM and MAX_MESSAGE_SIZE for GatewayZEVM have been added, enforcing limits on the sizes of payloads and messages in various functions. Corresponding error declarations, PayloadSizeExceeded and MessageSizeExceeded, have been introduced in their respective interfaces to enhance error handling. Additionally, new test cases have been implemented to ensure these validations are enforced during deposit and call operations.

Changes

File Path Change Summary
v2/contracts/evm/GatewayEVM.sol Added constant MAX_PAYLOAD_SIZE = 1024 and enforced payload size checks in depositAndCall and call functions. Introduced error PayloadSizeExceeded.
v2/contracts/evm/interfaces/IGatewayEVM.sol Added error PayloadSizeExceeded().
v2/contracts/zevm/GatewayZEVM.sol Added constant MAX_MESSAGE_SIZE = 1024 and enforced message size checks in withdrawAndCall, call, and withdraw functions. Removed empty message check. Introduced error MessageSizeExceeded.
v2/contracts/zevm/interfaces/IGatewayZEVM.sol Removed error EmptyMessage() and added error MessageSizeExceeded().
v2/test/GatewayEVM.t.sol Added tests for payload size validation: testDepositERC20ToCustodyWithPayloadFailsIfPayloadSizeExceeded, testDepositEthToTssWithPayloadFailsIfPayloadSizeExceeded, testCallWithPayloadFailsIfPayloadSizeExceeded.
v2/test/GatewayZEVM.t.sol Added tests for message size validation: testWithdrawAndCallZRC20FailsIfMessageSizeExceeded, testWithdrawAndCallZRC20WithCallOptsFailsIfMessageSizeExceeded, testWithdrawAndCallZETAFailsIfMessageSizeExceeded, testWithdrawAndCallZETAWithCallOptsFailsIfMessageSizeExceeded, testCallFailsIfMessageSizeExceeded, testCallWithCallOptsFailsIfMessageSizeExceeded.

Possibly related PRs

Suggested reviewers

  • fadeev
  • CharlieMc0
  • andresaiello
  • brewmaster012
  • fbac
  • lumtis

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.

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.

@skosito skosito linked an issue Oct 4, 2024 that may be closed by this pull request
@codecov-commenter
Copy link

codecov-commenter commented Oct 4, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 84.77%. Comparing base (a80faa8) to head (3b1de1a).
Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #376      +/-   ##
==========================================
+ Coverage   84.19%   84.77%   +0.57%     
==========================================
  Files           8        8              
  Lines         386      394       +8     
  Branches      126      134       +8     
==========================================
+ Hits          325      334       +9     
+ Misses         61       60       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@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: 18

🧹 Outside diff range and nitpick comments (10)
v2/contracts/evm/interfaces/IGatewayEVM.sol (3)

93-95: Approve new error with suggestions for improvement

The addition of the PayloadSizeExceeded error is a good step towards implementing the payload size limitation. However, consider the following suggestions to enhance its usefulness:

  1. Update the error comment to include the specific size limit (512 characters) mentioned in the PR objectives.
  2. Consider adding parameters to the error to provide more information when it's thrown. For example:
    error PayloadSizeExceeded(uint256 actualSize, uint256 maxSize);

Also, note that this interface file doesn't show the implementation of the actual size check. Ensure that the size check is implemented in the contract that implements this interface.

Would you like me to provide an example of how to modify the error declaration with these suggestions?


Line range hint 1-1: Enhance documentation for size limits

To fully implement the payload size limitation described in the PR objectives, consider the following suggestions:

  1. Add documentation about the 512-character size limit to relevant methods that accept bytes parameters (e.g., payload, data) and RevertOptions. For example:

    /// @notice Deposits ETH to the TSS address and calls an omnichain smart contract.
    /// @param receiver Address of the receiver.
    /// @param payload Calldata to pass to the call. Must be less than 512 characters.
    /// @param revertOptions Revert options. The revertMessage must be less than 512 characters.
    function depositAndCall(
        address receiver,
        bytes calldata payload,
        RevertOptions calldata revertOptions
    )
        external
        payable;
  2. Consider adding a constant for the size limit at the top of the file:

    /// @notice Maximum allowed length for payloads and revert messages
    uint256 constant MAX_PAYLOAD_SIZE = 512;

    This constant can then be referenced in the documentation and used in the implementing contract.

Would you like me to provide examples of how to add this documentation to specific methods?


Line range hint 1-1: Summary and response to PR questions

Thank you for implementing this payload size limitation. Here's a summary of the review and responses to your questions:

  1. The new PayloadSizeExceeded error is a good addition. Consider enhancing it with parameters and more specific documentation as suggested in the previous comments.

  2. To fully implement the size limit, add documentation about the 512-character limit to relevant methods and consider adding a constant for the limit.

Regarding your questions:

  1. Is the limit of 512 characters too small?

    • This depends on your specific use case. 512 characters should be sufficient for most scenarios, but you might want to analyze your typical payload sizes to ensure this limit doesn't unnecessarily restrict legitimate use cases.
  2. Should the size limit be configurable by an administrator?

    • Making the limit configurable adds flexibility but also complexity. If you anticipate needing different limits for different environments or expect the limit to change over time, then making it configurable could be beneficial. However, if you expect the limit to remain stable, a hard-coded constant might be simpler to maintain.

Consider discussing these points with your team to make a final decision on the size limit and its configurability.

Would you like suggestions on how to make the size limit configurable if you decide to go that route?

v2/contracts/zevm/interfaces/IGatewayZEVM.sol (1)

Line range hint 1-324: Summary: Message size limit implementation initiated, but further clarification needed.

The addition of the MessageSizeExceeded() error is a good start towards implementing the message and payload size limit as per the PR objectives. However, there are a few points that need to be addressed:

  1. The current implementation doesn't specify the actual size limit of 512 characters mentioned in the PR description. This limit should be clearly defined and enforced in the contract implementation.

  2. Regarding the questions posed in the PR description:
    a. Whether the limit of 512 characters is too small: This depends on the specific requirements of your system. Consider analyzing typical message sizes in your current usage and future needs to determine if 512 characters is sufficient.
    b. If the size limit should be configurable by an administrator: This could be a valuable feature for flexibility. Consider implementing a configurable limit using a setter function that can only be called by an admin role.

  3. The inconsistency between the AI summary and the visible changes (regarding the removal of EmptyMessage() error) needs to be clarified. If this error was indeed removed, ensure that any code relying on it is updated accordingly.

To fully implement the message size limit:

  1. Define a constant or state variable for the maximum message size.
  2. Implement checks in relevant functions (e.g., withdraw, withdrawAndCall, call) to ensure message size doesn't exceed the limit.
  3. If making the limit configurable, implement a setter function with appropriate access control.
  4. Update the MessageSizeExceeded error to include size information as suggested earlier.

Please address these points to complete the implementation of the message size limit feature.

v2/contracts/zevm/GatewayZEVM.sol (2)

39-41: Consider making MAX_MESSAGE_SIZE configurable

The addition of MAX_MESSAGE_SIZE constant aligns with the PR objective. However, consider the following points:

  1. The value of 512 characters seems arbitrary. It would be helpful to provide a comment explaining the rationale behind this specific limit.
  2. As per the PR description, there's a question about whether this limit should be configurable by an administrator. Consider implementing this as an immutable variable set in the constructor or as a configurable value with appropriate access controls.

If you decide to make it configurable, you could implement it like this:

uint256 public immutable MAX_MESSAGE_SIZE;

constructor(uint256 _maxMessageSize) {
    MAX_MESSAGE_SIZE = _maxMessageSize;
}

Or for runtime configurability (with appropriate access control):

uint256 public MAX_MESSAGE_SIZE;

function setMaxMessageSize(uint256 _maxMessageSize) external onlyAdmin {
    MAX_MESSAGE_SIZE = _maxMessageSize;
}

356-356: LGTM: Consistent message size check in non-transfer function

The message size check is consistently implemented in the call function, aligning with the checks in the withdrawAndCall functions. This is a good practice as it ensures that all cross-chain messages, regardless of whether they involve asset transfer, are subject to the same size limitations.

Consider adding a comment explaining why the size limit is also enforced for non-transfer calls. This could help future maintainers understand the rationale behind this decision.

v2/test/GatewayEVM.t.sol (3)

510-519: LGTM! Consider parameterizing the size limit.

The test case correctly verifies that the depositAndCall function fails when the payload size exceeds the limit. This aligns well with the PR objective of implementing size limitations for payloads and messages.

Consider parameterizing the size limit (currently hardcoded to 256 bytes) to make the test more flexible and easier to maintain if the limit changes in the future. For example:

+    uint256 constant MAX_PAYLOAD_SIZE = 256;
     function testDepositERC20ToCustodyWithPayloadFailsIfPayloadSizeExceeded() public {
         uint256 amount = 100_000;
-        bytes memory payload = new bytes(256);
-        revertOptions.revertMessage = new bytes(256);
+        bytes memory payload = new bytes(MAX_PAYLOAD_SIZE);
+        revertOptions.revertMessage = new bytes(MAX_PAYLOAD_SIZE);

         token.approve(address(gateway), amount);

         vm.expectRevert(PayloadSizeExceeded.selector);
         gateway.depositAndCall(destination, amount, address(token), payload, revertOptions);
     }

572-579: LGTM! Consider parameterizing the size limit.

This test case correctly verifies that the depositAndCall function fails for ETH deposits when the payload size exceeds the limit. The implementation is consistent with the ERC20 test case, which is good for maintaining code uniformity.

Similar to the previous suggestion, consider parameterizing the size limit to improve maintainability:

+    uint256 constant MAX_PAYLOAD_SIZE = 256;
     function testDepositEthToTssWithPayloadFailsIfPayloadSizeExceeded() public {
         uint256 amount = 100_000;
-        bytes memory payload = new bytes(256);
-        revertOptions.revertMessage = new bytes(256);
+        bytes memory payload = new bytes(MAX_PAYLOAD_SIZE);
+        revertOptions.revertMessage = new bytes(MAX_PAYLOAD_SIZE);

         vm.expectRevert(PayloadSizeExceeded.selector);
         gateway.depositAndCall{ value: amount }(destination, payload, revertOptions);
     }

Line range hint 510-611: Overall implementation looks good, with room for minor improvements.

The new test cases effectively verify the payload size limitation feature, which aligns well with the PR objectives. The implementation is consistent across different functions (ERC20 deposits, ETH deposits, and calls), which is a good practice.

To further improve the implementation:

  1. Consider parameterizing the MAX_PAYLOAD_SIZE as suggested in individual comments.
  2. Run the provided verification scripts to gather data on typical payload sizes and existing configurable limits. This will help in making informed decisions about:
    a. Whether the 512 character limit is appropriate.
    b. If the size limit should be made configurable by an admin.

After running the scripts and analyzing the results, you may want to:

  1. Adjust the MAX_PAYLOAD_SIZE if the current limit is too restrictive.
  2. Implement an admin-configurable limit if there's a need for flexibility or if other similar limits are configurable.
v2/contracts/evm/GatewayEVM.sol (1)

46-46: Re-evaluate the appropriateness of the 512-byte limit

The current MAX_PAYLOAD_SIZE is set to 512 bytes. Depending on the complexity of the payloads and revert messages, this limit might be restrictive. Consider analyzing typical payload sizes to determine if a higher limit is necessary to accommodate all valid use cases.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 8d665c0 and 3e534d5.

⛔ Files ignored due to path filters (77)
  • v2/docs/src/contracts/Revert.sol/interface.Revertable.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/Revert.sol/struct.RevertContext.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/Revert.sol/struct.RevertOptions.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/ERC20Custody.sol/contract.ERC20Custody.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/GatewayEVM.sol/contract.GatewayEVM.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/ZetaConnectorBase.sol/abstract.ZetaConnectorBase.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/ZetaConnectorNative.sol/contract.ZetaConnectorNative.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/ZetaConnectorNonNative.sol/contract.ZetaConnectorNonNative.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/interfaces/IERC20Custody.sol/interface.IERC20Custody.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/interfaces/IERC20Custody.sol/interface.IERC20CustodyErrors.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/interfaces/IERC20Custody.sol/interface.IERC20CustodyEvents.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/interfaces/IGatewayEVM.sol/interface.Callable.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/interfaces/IGatewayEVM.sol/interface.IGatewayEVM.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/interfaces/IGatewayEVM.sol/interface.IGatewayEVMErrors.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/interfaces/IGatewayEVM.sol/interface.IGatewayEVMEvents.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/interfaces/IGatewayEVM.sol/struct.MessageContext.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/interfaces/IZetaConnector.sol/interface.IZetaConnectorEvents.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/evm/interfaces/IZetaNonEthNew.sol/interface.IZetaNonEthNew.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/GatewayZEVM.sol/contract.GatewayZEVM.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/SystemContract.sol/contract.SystemContract.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/SystemContract.sol/interface.SystemContractErrors.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/ZRC20.sol/contract.ZRC20.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/ZRC20.sol/interface.ZRC20Errors.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/IGatewayZEVM.sol/interface.IGatewayZEVM.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/IGatewayZEVM.sol/interface.IGatewayZEVMErrors.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/IGatewayZEVM.sol/interface.IGatewayZEVMEvents.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/IGatewayZEVM.sol/struct.CallOptions.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/ISystem.sol/interface.ISystem.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/IWZETA.sol/interface.IWETH9.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/IZRC20.sol/enum.CoinType.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/IZRC20.sol/interface.IZRC20.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/IZRC20.sol/interface.IZRC20Metadata.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/IZRC20.sol/interface.ZRC20Events.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/UniversalContract.sol/interface.UniversalContract.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/UniversalContract.sol/interface.zContract.md is excluded by !v2/docs/**
  • v2/docs/src/contracts/zevm/interfaces/UniversalContract.sol/struct.zContext.md is excluded by !v2/docs/**
  • v2/pkg/erc20custody.sol/erc20custody.go is excluded by !v2/pkg/**
  • v2/pkg/erc20custody.t.sol/erc20custodytest.go is excluded by !v2/pkg/**
  • v2/pkg/erc20custodyechidnatest.sol/erc20custodyechidnatest.go is excluded by !v2/pkg/**
  • v2/pkg/gatewayevm.sol/gatewayevm.go is excluded by !v2/pkg/**
  • v2/pkg/gatewayevm.t.sol/gatewayevminboundtest.go is excluded by !v2/pkg/**
  • v2/pkg/gatewayevm.t.sol/gatewayevmtest.go is excluded by !v2/pkg/**
  • v2/pkg/gatewayevmechidnatest.sol/gatewayevmechidnatest.go is excluded by !v2/pkg/**
  • v2/pkg/gatewayevmupgrade.t.sol/gatewayevmuupsupgradetest.go is excluded by !v2/pkg/**
  • v2/pkg/gatewayevmupgradetest.sol/gatewayevmupgradetest.go is excluded by !v2/pkg/**
  • v2/pkg/gatewayevmzevm.t.sol/gatewayevmzevmtest.go is excluded by !v2/pkg/**
  • v2/pkg/gatewayzevm.sol/gatewayzevm.go is excluded by !v2/pkg/**
  • v2/pkg/gatewayzevm.t.sol/gatewayzevminboundtest.go is excluded by !v2/pkg/**
  • v2/pkg/gatewayzevm.t.sol/gatewayzevmoutboundtest.go is excluded by !v2/pkg/**
  • v2/pkg/igatewayevm.sol/igatewayevm.go is excluded by !v2/pkg/**
  • v2/pkg/igatewayevm.sol/igatewayevmerrors.go is excluded by !v2/pkg/**
  • v2/pkg/igatewayzevm.sol/igatewayzevm.go is excluded by !v2/pkg/**
  • v2/pkg/igatewayzevm.sol/igatewayzevmerrors.go is excluded by !v2/pkg/**
  • v2/pkg/receiverevm.sol/receiverevm.go is excluded by !v2/pkg/**
  • v2/pkg/senderzevm.sol/senderzevm.go is excluded by !v2/pkg/**
  • v2/pkg/zetaconnectornative.sol/zetaconnectornative.go is excluded by !v2/pkg/**
  • v2/pkg/zetaconnectornative.t.sol/zetaconnectornativetest.go is excluded by !v2/pkg/**
  • v2/pkg/zetaconnectornonnative.sol/zetaconnectornonnative.go is excluded by !v2/pkg/**
  • v2/pkg/zetaconnectornonnative.t.sol/zetaconnectornonnativetest.go is excluded by !v2/pkg/**
  • v2/pkg/zrc20.t.sol/zrc20test.go is excluded by !v2/pkg/**
  • v2/types/GatewayEVM.ts is excluded by !v2/types/**
  • v2/types/GatewayEVMEchidnaTest.ts is excluded by !v2/types/**
  • v2/types/GatewayZEVM.ts is excluded by !v2/types/**
  • v2/types/factories/ERC20CustodyEchidnaTest__factory.ts is excluded by !v2/types/**
  • v2/types/factories/ERC20Custody__factory.ts is excluded by !v2/types/**
  • v2/types/factories/GatewayEVMEchidnaTest__factory.ts is excluded by !v2/types/**
  • v2/types/factories/GatewayEVMUpgradeTest__factory.ts is excluded by !v2/types/**
  • v2/types/factories/GatewayEVM__factory.ts is excluded by !v2/types/**
  • v2/types/factories/GatewayZEVM__factory.ts is excluded by !v2/types/**
  • v2/types/factories/IGatewayEVM.sol/IGatewayEVMErrors__factory.ts is excluded by !v2/types/**
  • v2/types/factories/IGatewayEVM.sol/IGatewayEVM__factory.ts is excluded by !v2/types/**
  • v2/types/factories/IGatewayZEVM.sol/IGatewayZEVMErrors__factory.ts is excluded by !v2/types/**
  • v2/types/factories/IGatewayZEVM.sol/IGatewayZEVM__factory.ts is excluded by !v2/types/**
  • v2/types/factories/ReceiverEVM__factory.ts is excluded by !v2/types/**
  • v2/types/factories/SenderZEVM__factory.ts is excluded by !v2/types/**
  • v2/types/factories/ZetaConnectorNative__factory.ts is excluded by !v2/types/**
  • v2/types/factories/ZetaConnectorNonNative__factory.ts is excluded by !v2/types/**
📒 Files selected for processing (6)
  • v2/contracts/evm/GatewayEVM.sol (4 hunks)
  • v2/contracts/evm/interfaces/IGatewayEVM.sol (1 hunks)
  • v2/contracts/zevm/GatewayZEVM.sol (7 hunks)
  • v2/contracts/zevm/interfaces/IGatewayZEVM.sol (1 hunks)
  • v2/test/GatewayEVM.t.sol (3 hunks)
  • v2/test/GatewayZEVM.t.sol (6 hunks)
🔇 Additional comments (6)
v2/contracts/zevm/interfaces/IGatewayZEVM.sol (1)

89-91: LGTM: New error for message size limit added.

The addition of the MessageSizeExceeded() error aligns well with the PR objective to limit payload and message size. This error will help in handling cases where the message size exceeds the allowed limit in external functions.

v2/contracts/zevm/GatewayZEVM.sol (4)

223-223: LGTM: Consistent implementation of message size check

The message size check here is consistent with the previous withdrawAndCall function overload. This consistency is good for maintainability and reduces the chance of errors.


291-291: LGTM: Consistent message size check across overloads

The message size check is consistently implemented across all overloads of withdrawAndCall. This consistency is crucial for maintaining the integrity of the size limit across different function signatures.


Line range hint 1-556: Summary of changes and recommendations

The implemented changes consistently add a message size check across multiple functions, aligning well with the PR objectives. Here's a summary of the key points and recommendations:

  1. The MAX_MESSAGE_SIZE constant is added, but consider making it configurable as per the PR description's question.
  2. The message size checks are consistently implemented across all relevant functions, which is good for maintainability.
  3. Consider clarifying whether messages exactly 512 characters long should be allowed or not (>= vs > in the condition).
  4. Ensure that the MessageSizeExceeded error is properly defined in the contract.
  5. Consider adding a comment explaining the rationale for applying the size limit to non-transfer calls.

Overall, the changes appear to be well-implemented and achieve the desired objective of limiting message sizes.


184-184: Verify the intended behavior for MAX_MESSAGE_SIZE limit

The added check for message size aligns with the PR objective. However, there are a couple of points to consider:

  1. The condition >= will reject messages that are exactly 512 characters long. If the intention is to allow messages up to and including 512 characters, consider changing this to >.

  2. The error MessageSizeExceeded is not defined in the provided code snippet. Ensure it's properly defined elsewhere in the contract.

To ensure consistency across the codebase, let's check for other occurrences of this error:

✅ Verification successful

MessageSizeExceeded is properly defined and used consistently across the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

rg "error MessageSizeExceeded" --type solidity

Length of output: 81


Script:

#!/bin/bash
# Searching for the occurrence of 'MessageSizeExceeded' error in Solidity files
rg "MessageSizeExceeded" -g "*.sol"

Length of output: 2102

v2/test/GatewayEVM.t.sol (1)

605-611: LGTM! Consider parameterizing the size limit and addressing PR questions.

This test case correctly verifies that the call function fails when the payload size exceeds the limit. The implementation is consistent with the previous test cases, which is excellent for maintaining code uniformity.

As suggested for the previous test cases, consider parameterizing the size limit:

+    uint256 constant MAX_PAYLOAD_SIZE = 256;
     function testCallWithPayloadFailsIfPayloadSizeExceeded() public {
-        bytes memory payload = new bytes(256);
-        revertOptions.revertMessage = new bytes(256);
+        bytes memory payload = new bytes(MAX_PAYLOAD_SIZE);
+        revertOptions.revertMessage = new bytes(MAX_PAYLOAD_SIZE);

         vm.expectRevert(PayloadSizeExceeded.selector);
         gateway.call(destination, payload, revertOptions);
     }

Regarding the questions raised in the PR description:

  1. Is the limit of 512 characters too small?
    To verify this, we need to analyze the typical payload sizes in the current implementation:

  2. Should the size limit be configurable by an admin?
    To determine if this is necessary, let's check if there are any existing configurable limits in the contract:

These scripts will help gather information to make informed decisions about the payload size limit and its configurability.

Comment on lines +89 to +91

/// @notice Error indicating message size exceeded in external functions.
error MessageSizeExceeded();
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding size information to the error.

While the MessageSizeExceeded() error is functional, it could be more informative. Consider modifying it to include the actual message size and the maximum allowed size. This would provide more context when the error is thrown.

Here's a suggested improvement:

/// @notice Error indicating message size exceeded in external functions.
/// @param actualSize The size of the message that exceeded the limit.
/// @param maxSize The maximum allowed size for messages.
error MessageSizeExceeded(uint256 actualSize, uint256 maxSize);

This change would allow for more detailed error reporting and easier debugging.

@@ -42,6 +42,8 @@ contract GatewayEVM is
bytes32 public constant ASSET_HANDLER_ROLE = keccak256("ASSET_HANDLER_ROLE");
/// @notice New role identifier for pauser role.
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
/// @notice Max payload size.
uint256 public constant MAX_PAYLOAD_SIZE = 512;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider making MAX_PAYLOAD_SIZE configurable

To provide flexibility for future updates or varying use cases, consider allowing MAX_PAYLOAD_SIZE to be adjustable by an administrator through a setter function. This would enable changes to the payload size limit without requiring a contract redeployment.

@@ -294,6 +296,7 @@
{
if (msg.value == 0) revert InsufficientETHAmount();
if (receiver == address(0)) revert ZeroAddress();
if (payload.length + revertOptions.revertMessage.length >= MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor repeated payload size checks into a private function

The payload size validation is repeated in multiple functions. Consider extracting this logic into a private helper function to enhance code maintainability and reduce duplication.

Example:

function _validatePayloadSize(bytes calldata payload, RevertOptions calldata revertOptions) private view {
    if (payload.length + revertOptions.revertMessage.length > MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
}

Then, replace the checks in the functions with a call to this helper function.

Also applies to: 327-327, 348-348


⚠️ Potential issue

Off-by-one error in payload size check

The condition >= MAX_PAYLOAD_SIZE will revert when the combined payload size is exactly MAX_PAYLOAD_SIZE. If the intention is to allow payloads up to and including MAX_PAYLOAD_SIZE bytes, the comparison should use > instead of >=.

Apply this diff to correct the comparison operator:

- if (payload.length + revertOptions.revertMessage.length >= MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
+ if (payload.length + revertOptions.revertMessage.length > MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
📝 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
if (payload.length + revertOptions.revertMessage.length >= MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
if (payload.length + revertOptions.revertMessage.length > MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();

@@ -321,6 +324,7 @@
{
if (amount == 0) revert InsufficientERC20Amount();
if (receiver == address(0)) revert ZeroAddress();
if (payload.length + revertOptions.revertMessage.length >= MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Off-by-one error in payload size check

Similar to the previous issue, the condition >= MAX_PAYLOAD_SIZE may incorrectly revert valid payloads that are exactly at the maximum allowed size.

Apply this diff to correct the comparison operator:

- if (payload.length + revertOptions.revertMessage.length >= MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
+ if (payload.length + revertOptions.revertMessage.length > MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
📝 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
if (payload.length + revertOptions.revertMessage.length >= MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
if (payload.length + revertOptions.revertMessage.length > MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();

@@ -341,6 +345,8 @@
nonReentrant
{
if (receiver == address(0)) revert ZeroAddress();
if (payload.length + revertOptions.revertMessage.length >= MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Off-by-one error in payload size check

Consistent with earlier observations, updating the comparison operator ensures that payloads of exactly MAX_PAYLOAD_SIZE bytes are accepted as valid.

Apply this diff to correct the comparison operator:

- if (payload.length + revertOptions.revertMessage.length >= MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
+ if (payload.length + revertOptions.revertMessage.length > MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
📝 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
if (payload.length + revertOptions.revertMessage.length >= MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();
if (payload.length + revertOptions.revertMessage.length > MAX_PAYLOAD_SIZE) revert PayloadSizeExceeded();

Comment on lines 224 to 230
function testWithdrawAndCallZRC20WithCallOptsFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(256);
revertOptions.revertMessage = new bytes(256);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.withdrawAndCall(abi.encodePacked(addr1), 1, address(zrc20), message, callOptions, revertOptions);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Verify message size limit consistency across tests

Similar to a previous comment, ensure that the message size limit in this test aligns with the PR objectives.


🛠️ Refactor suggestion

Use a constant for the message size limit instead of hardcoding 256

In the test function testWithdrawAndCallZRC20WithCallOptsFailsIfMessageSizeExceeded, the message size limit is hardcoded. Defining a constant for the message size limit enhances maintainability.

Apply this diff:

+    uint256 constant MESSAGE_SIZE_LIMIT = 256;
+
     function testWithdrawAndCallZRC20WithCallOptsFailsIfMessageSizeExceeded() public {
-        bytes memory message = new bytes(256);
-        revertOptions.revertMessage = new bytes(256);
+        bytes memory message = new bytes(MESSAGE_SIZE_LIMIT);
+        revertOptions.revertMessage = new bytes(MESSAGE_SIZE_LIMIT);
📝 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 testWithdrawAndCallZRC20WithCallOptsFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(256);
revertOptions.revertMessage = new bytes(256);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.withdrawAndCall(abi.encodePacked(addr1), 1, address(zrc20), message, callOptions, revertOptions);
}
uint256 constant MESSAGE_SIZE_LIMIT = 256;
function testWithdrawAndCallZRC20WithCallOptsFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(MESSAGE_SIZE_LIMIT);
revertOptions.revertMessage = new bytes(MESSAGE_SIZE_LIMIT);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.withdrawAndCall(abi.encodePacked(addr1), 1, address(zrc20), message, callOptions, revertOptions);
}

Comment on lines 303 to 309
function testWithdrawAndCallZETAFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(256);
revertOptions.revertMessage = new bytes(256);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.withdrawAndCall(abi.encodePacked(addr1), 1, 1, message, revertOptions);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Confirm message size limit matches PR objectives

Ensure the message size limit used here is consistent with the 512-character limit mentioned in the PR objectives.


🛠️ Refactor suggestion

Abstract message size limit into a constant

To avoid duplication and magic numbers, define a constant for the message size limit in testWithdrawAndCallZETAFailsIfMessageSizeExceeded.

+    uint256 constant MESSAGE_SIZE_LIMIT = 256;
+
     function testWithdrawAndCallZETAFailsIfMessageSizeExceeded() public {
-        bytes memory message = new bytes(256);
-        revertOptions.revertMessage = new bytes(256);
+        bytes memory message = new bytes(MESSAGE_SIZE_LIMIT);
+        revertOptions.revertMessage = new bytes(MESSAGE_SIZE_LIMIT);
📝 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 testWithdrawAndCallZETAFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(256);
revertOptions.revertMessage = new bytes(256);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.withdrawAndCall(abi.encodePacked(addr1), 1, 1, message, revertOptions);
}
uint256 constant MESSAGE_SIZE_LIMIT = 256;
function testWithdrawAndCallZETAFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(MESSAGE_SIZE_LIMIT);
revertOptions.revertMessage = new bytes(MESSAGE_SIZE_LIMIT);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.withdrawAndCall(abi.encodePacked(addr1), 1, 1, message, revertOptions);
}

Comment on lines 322 to 328
function testWithdrawAndCallZETAWithCallOptsFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(256);
revertOptions.revertMessage = new bytes(256);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.withdrawAndCall(abi.encodePacked(addr1), 1, 1, message, callOptions, revertOptions);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Check for consistency with PR objectives on message size limit

Again, verify that the limit used here reflects the intention in the PR objectives.


🛠️ Refactor suggestion

Avoid hardcoding the message size limit

In testWithdrawAndCallZETAWithCallOptsFailsIfMessageSizeExceeded, consider using a constant for the message size limit.

+    uint256 constant MESSAGE_SIZE_LIMIT = 256;
+
     function testWithdrawAndCallZETAWithCallOptsFailsIfMessageSizeExceeded() public {
-        bytes memory message = new bytes(256);
-        revertOptions.revertMessage = new bytes(256);
+        bytes memory message = new bytes(MESSAGE_SIZE_LIMIT);
+        revertOptions.revertMessage = new bytes(MESSAGE_SIZE_LIMIT);
📝 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 testWithdrawAndCallZETAWithCallOptsFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(256);
revertOptions.revertMessage = new bytes(256);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.withdrawAndCall(abi.encodePacked(addr1), 1, 1, message, callOptions, revertOptions);
}
uint256 constant MESSAGE_SIZE_LIMIT = 256;
function testWithdrawAndCallZETAWithCallOptsFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(MESSAGE_SIZE_LIMIT);
revertOptions.revertMessage = new bytes(MESSAGE_SIZE_LIMIT);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.withdrawAndCall(abi.encodePacked(addr1), 1, 1, message, callOptions, revertOptions);
}

Comment on lines 540 to 546
function testCallFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(256);
revertOptions.revertMessage = new bytes(256);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.call(abi.encodePacked(addr1), address(zrc20), message, 1, revertOptions);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Align message size limit with PR objectives

Ensure that the test reflects the intended message size limit of less than 512 characters.


🛠️ Refactor suggestion

Refactor to use a constant for message size limit

In testCallFailsIfMessageSizeExceeded, refactoring to use a constant enhances code clarity.

+    uint256 constant MESSAGE_SIZE_LIMIT = 256;
+
     function testCallFailsIfMessageSizeExceeded() public {
-        bytes memory message = new bytes(256);
-        revertOptions.revertMessage = new bytes(256);
+        bytes memory message = new bytes(MESSAGE_SIZE_LIMIT);
+        revertOptions.revertMessage = new bytes(MESSAGE_SIZE_LIMIT);
📝 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 testCallFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(256);
revertOptions.revertMessage = new bytes(256);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.call(abi.encodePacked(addr1), address(zrc20), message, 1, revertOptions);
}
uint256 constant MESSAGE_SIZE_LIMIT = 256;
function testCallFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(MESSAGE_SIZE_LIMIT);
revertOptions.revertMessage = new bytes(MESSAGE_SIZE_LIMIT);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.call(abi.encodePacked(addr1), address(zrc20), message, 1, revertOptions);
}

Comment on lines 567 to 573
function testCallWithCallOptsFailsIfMessageSizeExceeded() public {
bytes memory message = new bytes(256);
revertOptions.revertMessage = new bytes(256);
vm.expectRevert(MessageSizeExceeded.selector);
gateway.call(abi.encodePacked(addr1), address(zrc20), message, callOptions, revertOptions);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Verify consistency of message size limit with PR objectives

Double-check that the message size limit in this test corresponds with the 512-character limit discussed in the PR objectives.


🛠️ Refactor suggestion

Use a defined constant for message size limit

Consistently using a constant for the message size limit in testCallWithCallOptsFailsIfMessageSizeExceeded will improve maintainability.

+    uint256 constant MESSAGE_SIZE_LIMIT = 256;
+
     function testCallWithCallOptsFailsIfMessageSizeExceeded() public {
-        bytes memory message = new bytes(256);
-        revertOptions.revertMessage = new bytes(256);
+        bytes memory message = new bytes(MESSAGE_SIZE_LIMIT);
+        revertOptions.revertMessage = new bytes(MESSAGE_SIZE_LIMIT);

Committable suggestion was skipped due to low confidence.

@fbac
Copy link
Contributor

fbac commented Oct 4, 2024

limits payload/message len + revertOptions.revertMessage len < 512

questions:

  • is this too small?
  • should we make limit size configurable by admin so we can change it with setter?

Is this based on an issue raised by an audit?

v2/contracts/evm/GatewayEVM.sol Outdated Show resolved Hide resolved
v2/contracts/evm/GatewayEVM.sol Outdated Show resolved Hide resolved
@skosito skosito requested a review from lumtis October 4, 2024 15:05
Copy link
Member

@lumtis lumtis left a comment

Choose a reason for hiding this comment

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

Looks good

@skosito skosito merged commit cbbcf27 into main Oct 4, 2024
11 checks passed
@skosito skosito deleted the limit-msg-and-payload-size branch October 4, 2024 16:35
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.

Add limits for all user input data
4 participants