tests: add solver delegate coverage#3
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive test suite for the Solver7702Delegate contract, including unit, integration, and fork tests, along with necessary mocks and gas snapshots. It also adds documentation to the fallback function regarding the expected calldata format. Feedback focuses on correcting the invalid Solidity pragma version 0.8.34 to a stable release and improving fuzz test coverage by allowing empty payloads instead of substituting them with 0x00.
There was a problem hiding this comment.
Pull request overview
Adds a comprehensive Foundry test suite around Solver7702Delegate’s EIP-7702 delegated fallback forwarding behavior, including unit, integration (mock GPv2), and fork-based regression tests.
Changes:
- Added unit/integration/fork tests plus supporting mocks and utilities for constructing settlement-like calldata and revert/return-data scenarios.
- Added gas snapshot JSONs for the new test suites.
- Updated tooling/config (test solhint overrides, coverage exclusions to ignore
lib/, Foundry remappings,.env.example, and OpenZeppelin submodule pin).
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| test/utils/SettlementUtils.sol | Utility library to build mock/real GPv2 settlement calldata for integration/fork tests. |
| test/utils/MathUtils.sol | Small test-only math helper library. |
| test/Solver7702Delegate.t.sol | Unit tests covering constructor behavior and fallback forwarding/revert bubbling. |
| test/Solver7702Delegate.integration.t.sol | Integration tests using mocked GPv2 settlement/authenticator. |
| test/Solver7702Delegate.fork.t.sol | Fork tests against real GPv2 settlement across networks plus historical calldata replay. |
| test/mocks/targets/RevertingTarget.sol | Target contract producing standard Solidity revert shapes (custom error/string/panic/empty). |
| test/mocks/targets/RawRevertTarget.sol | Target contract that reverts with arbitrary raw bytes. |
| test/mocks/targets/PayableFallbackTarget.sol | Payable fallback/receive target used to assert exact forwarding semantics. |
| test/mocks/targets/NonpayableTarget.sol | Nonpayable target used to assert value-forwarding failure behavior. |
| test/mocks/MockSettlement.sol | Simple payable settlement-like target for delegate integration tests. |
| test/mocks/MockGPv2Settlement.sol | Minimal GPv2 settlement mock that checks solver allowlist and executes interactions. |
| test/mocks/MockGPv2Authenticator.sol | Minimal solver allowlist mock used by integration tests. |
| test/dependencies/settlement/IGPv2Settlement.sol | Test-local GPv2 settlement interface/types used by mocks and calldata builders. |
| test/dependencies/settlement/IGPv2Authenticator.sol | Test-local GPv2 authenticator interface used by mocks. |
| test/BaseTest.t.sol | Shared test harness: approved callers, packed calldata helper, delegation attachment helper. |
| test/.solhint.json | Test-folder solhint overrides to accommodate patterns used in the new tests. |
| src/Solver7702Delegate.sol | Added calldata-format documentation to the fallback function. |
| snapshots/Solver7702DelegateTest.json | Gas snapshot baselines for unit tests. |
| snapshots/Solver7702DelegateIntegrationTest.json | Gas snapshot baselines for integration tests. |
| snapshots/Solver7702DelegateForkTest.json | Gas snapshot baselines for fork tests. |
| Justfile | Adjusted test/coverage commands (including excluding lib/ from coverage). |
| foundry.toml | Added OpenZeppelin remapping and formatting adjustment. |
| foundry.lock | Added OpenZeppelin submodule pin. |
| .gitmodules | Added OpenZeppelin contracts submodule. |
| .env.example | Added RPC URL environment variables for fork testing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
kaze-cow
left a comment
There was a problem hiding this comment.
Good start! The tests could use more foundry provided utilities and there were some unusual patterns that I couldn't figure out.
| @@ -0,0 +1,609 @@ | |||
| // SPDX-License-Identifier: MIT OR Apache-2.0 | |||
| // solhint-disable avoid-low-level-calls, gas-small-strings, max-states-count | |||
There was a problem hiding this comment.
if practical it would be good to only disable next line rathre than disabling the whole file. Otherwise it is easy to miss out on legitimate checks (or understand why they are needed to be disabled in the first place)
There was a problem hiding this comment.
I agree it isn't good to do this kind of global ignore for the aforementioned reasons.
I'd argue in the other direction though: most of these should be ignored for all tests, we should even add ignores to the template.
avoid-low-level-calls, this is the only one I'd possibly keep, it's nice for readability if we use proper calls and it's ok to add in-line exceptions when needed.gas-small-strings, this is for gas efficiency and tests shouldn't be developed with gas efficiency in mind.max-states-count, I think it's fine if tests that need it have a lot of state, so it's fine to remove them globally. If you think this helps keeping the tests simple, we can keep it however.
There was a problem hiding this comment.
low level calls are particularly useful when calling a delegate contract because there are no signatures to be called there, so we simply pack the data in the expected format (targetAddress + calldata) and call the solver directly.
fedgiac
left a comment
There was a problem hiding this comment.
Very quick review on my part, I like how tests are structured but there are a few things I don't understand.
| @@ -0,0 +1,609 @@ | |||
| // SPDX-License-Identifier: MIT OR Apache-2.0 | |||
| // solhint-disable avoid-low-level-calls, gas-small-strings, max-states-count | |||
There was a problem hiding this comment.
I agree it isn't good to do this kind of global ignore for the aforementioned reasons.
I'd argue in the other direction though: most of these should be ignored for all tests, we should even add ignores to the template.
avoid-low-level-calls, this is the only one I'd possibly keep, it's nice for readability if we use proper calls and it's ok to add in-line exceptions when needed.gas-small-strings, this is for gas efficiency and tests shouldn't be developed with gas efficiency in mind.max-states-count, I think it's fine if tests that need it have a lot of state, so it's fine to remove them globally. If you think this helps keeping the tests simple, we can keep it however.
|
The tests are significantly simpler and have had a major rework, so some reviews might be outdated. |
kaze-cow
left a comment
There was a problem hiding this comment.
I was able to try out the new fork tests! super nice, ergonomic. only minor things left.
I noticed that the gas snapshots measuring how much gas was used for each different approved caller appears to have been removed. I actually liked this breakdown--any chance we can bring it back?
worth mentioning that rollFork unfortunately does take a lot of time because it has to replay all the transactions prior to the target one to get a perfect simulation. But its a 1st time thing only because anvil caches previous calls to disk.
kaze-cow
left a comment
There was a problem hiding this comment.
all of my remaining comments were addressed. We can get rid of BASE_RPC_URL by using a different transaction (discussed in private call), so once that is resolved I am happy to merge.
* feat: setup * update README * update README * Update README.md * added deploy script * pr feedback * tests: add solver delegate coverage (#3) * tests: wip * better tests * unit tests * refactor * integration tests * fork tests * check snapshots in CI * add other networks * more precise snapshot * test: address PR review comments * add rpc urls to env * fix tests * simplify tests * pr feedback * remove OZ, update tests * apply copilot recommendation to use msg.value appropriately in historical txs * update snapshots * pr feedback * add swap and bridge tx
Summary
This PR adds focused test coverage for
Solver7702Delegate.What changed
bytes20(target) || payloadcalldataCOW_HISTORICAL_TX_HASHES.vm.etchto simulate the EIP-7702 delegation.ETH_MAINNET_RPC_URL; despite the name, it can point to another network when replaying tx hashes from that network.How to test custom transactions
The supplied tx hashes must exist on the RPC's network, and the RPC must support the historical state needed by
vm.rollFork(txHash).Test plan
Run: