Skip to content

Conversation

devin-ai-integration[bot]
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Sep 5, 2025

Enhance L2StandardBridge test coverage with comprehensive fuzz tests and eliminate code duplication

Summary

This PR converts three regular tests to fuzz tests (withdraw_ether, withdraw_withdrawingERC20, withdrawTo_withdrawingERC20), adds missing test coverage for the l1TokenBridge() function, and significantly refactors helper functions to eliminate code duplication while adding comprehensive cross-domain messaging expectations to fuzz tests.

Key Changes:

  • Fuzz test conversion: Tests now validate a wide range of amounts (1-1,000,000) and gas limits (21,000-1,000,000) instead of hardcoded values
  • Helper function refactoring: Broke down duplicated _preBridgeERC20 and _preBridgeERC20To functions into a parameterized _expectERC20WithdrawalCalls system with 4 smaller functions
  • Comprehensive expectations: Fuzz tests now include all cross-domain messaging expectations (baseGas calculation, withdrawal hash, vm.expectCall for full call chain, comprehensive events)
  • New coverage: Added test for previously uncovered l1TokenBridge() function

Review & Testing Checklist for Human

This is a medium-risk refactoring that requires careful validation of complex helper function changes:

  • Verify helper function equivalence: Run both old and new helper functions side-by-side to ensure identical expectations are generated
  • Test conditional bridge logic: Manually verify that _expectBridgeCalls correctly handles withdraw vs withdrawTo based on recipient address
  • Validate fuzz boundaries: Confirm that amount bounds (1-1,000,000) and gas limit bounds (21,000-1,000,000) are appropriate and don't exclude important edge cases
  • Run heavy fuzz testing: Execute FOUNDRY_PROFILE=ciheavy forge test --match-path test/L2/L2StandardBridge.t.sol --match-test "testFuzz_withdraw_withdrawingERC20_succeeds|testFuzz_withdrawTo_withdrawingERC20_succeeds" to catch potential edge case failures

Notes

  • This addresses alcueca's feedback about missing _preBridgeERC20 logic in fuzz tests and code duplication concerns
  • The refactoring eliminates ~80 lines of duplicated code while maintaining identical test coverage
  • All 25 tests pass locally and the critical "contracts-bedrock-tests-heavy-fuzz-modified" CI check now passes
  • Link to Devin run: https://app.devin.ai/sessions/970ca21f44774d2694ab3dc1946f9a32
  • Requested by: @aliersh

- add test for uncovered l1TokenBridge() function
- convert 3 tests to fuzz tests for broader coverage:
  - testFuzz_withdraw_withdrawingERC20_succeeds
  - testFuzz_withdraw_ether_succeeds
  - testFuzz_withdrawTo_withdrawingERC20_succeeds
- enhance test organization and documentation
- add proper event expectations for fuzz tests
@devin-ai-integration devin-ai-integration bot requested a review from a team as a code owner September 5, 2025 20:39
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@tynes
Copy link
Contributor

tynes commented Sep 5, 2025

nice

Copy link

codecov bot commented Sep 5, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.84%. Comparing base (8328a42) to head (8a3c6ff).
⚠️ Report is 43 commits behind head on develop.

Additional details and impacted files
@@           Coverage Diff            @@
##           develop   #17347   +/-   ##
========================================
  Coverage    95.84%   95.84%           
========================================
  Files          110      110           
  Lines         5102     5102           
========================================
  Hits          4890     4890           
  Misses         212      212           
Flag Coverage Δ
contracts-bedrock-tests 95.84% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@smartcontracts smartcontracts left a comment

Choose a reason for hiding this comment

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

nice good pr

@smartcontracts
Copy link
Contributor

devin you need to run forge fmt to format this

@aliersh
Copy link
Contributor

aliersh commented Sep 5, 2025

DevinAI, there are failed CI checks. Fix them.

- Add _minGasLimit parameter to testFuzz_withdraw_withdrawingERC20_succeeds
- Add _minGasLimit parameter to testFuzz_withdrawTo_withdrawingERC20_succeeds
- Use consistent bounds (21000, 1000000) matching testFuzz_withdraw_ether_succeeds
- Addresses alcueca's PR comment about fuzzing minGasLimit parameter
_amount = bound(_amount, 1, 1000000);
_minGasLimit = uint32(bound(_minGasLimit, 21000, 1000000));

deal(address(L2Token), alice, _amount, true);
Copy link
Contributor

@alcueca alcueca Sep 15, 2025

Choose a reason for hiding this comment

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

Devinai, this is missing a lot of the logic included in _preBridgeERC20, are we sure we don't need that logic anymore?

Also, now we have a lot more lines and code repeated between both tests and assumedly _preBridgeERC20.

Maybe we should first see if we need to refactor _preBridgeERC20, and what is best in terms of code economy and clarity.

…uzz tests

- Create parameterized _expectERC20WithdrawalCalls helper to eliminate code duplication
- Add comprehensive vm.expectCall statements for cross-domain messaging, token burns, and events
- Include withdrawal hash calculation and cross-domain message encoding in fuzz tests
- Fix vm.expectCall logic to properly handle both withdraw and withdrawTo functions
- Address alcueca's feedback about missing _preBridgeERC20 logic in fuzz tests
internal
{
deal(_l2Token, alice, _amount, true);
assertEq(ERC20(_l2Token).balanceOf(alice), _amount);
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't make sense to have this deal inside a _expectERC20WithdrawalCalls function.

Copy link
Contributor

Choose a reason for hiding this comment

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

devinai same as above


_expectWithdrawalCallsAndEvents(_amount, _minGasLimit, _to, _isLegacy, _l2Token);

vm.prank(alice, alice);
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't make sense to have this vm.prank at the end of a _expectERC20WithdrawalCalls function.

vm.expectCall(
address(l2StandardBridge), abi.encodeCall(l2StandardBridge.withdraw, (_l2Token, 100, 1000, hex""))
);
if (_to == alice) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is an unclear condition to discriminate between withdraw and withdrawTo. Maybe pass an enum as an argument to do that job.

Copy link
Contributor

Choose a reason for hiding this comment

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

devinai agree it's weird to have alice here hard-coded, if anything this should be both a boolean input as well as having the recipient address be an input

// Alice has 100 L2Token
deal(_l2Token, alice, 100, true);
assertEq(ERC20(_l2Token).balanceOf(alice), 100);
function _expectERC20WithdrawalCalls(
Copy link
Contributor

@alcueca alcueca Sep 16, 2025

Choose a reason for hiding this comment

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

I think that the tests should implement deal and vm.prank themselves and call _expectWithdrawalCallsAndEvents.

Copy link
Contributor

Choose a reason for hiding this comment

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

devinai I agree here, it's weird to have an expect (assertion) function doing stateful things that manipulate the test state, leave the tests to do that


vm.prank(alice, alice);
function _preBridgeERC20(bool _isLegacy, address _l2Token) internal {
_expectERC20WithdrawalCalls(100, 1000, alice, _isLegacy, _l2Token);
}

/// @notice Sets up expected calls and emits for a successful ERC20 withdrawal to a different
/// recipient.
/// @dev `withdrawTo` and `bridgeERC20To` should behave the same when transferring ERC20 tokens
/// so they should share the same setup and expectEmit calls
function _preBridgeERC20To(bool _isLegacy, address _l2Token) internal {
Copy link
Contributor

Choose a reason for hiding this comment

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

Tbh, at this point I would refactor the other four tests that use _preBridgeERC20 or _preBridgeERC20To, and deprecate these two functions. Otherwise we leave a half done refactor which is worse than no refactor at all.

Copy link
Contributor

Choose a reason for hiding this comment

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

devinai agreed, no reason for these functions anymore

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