Phase 1 of fuzzing: scaffolding + first real test (#64)#130
Draft
ivanvpan wants to merge 4 commits into
Draft
Conversation
Introduce test/fuzz with MockERC20, MockDistributionManagerForFuzz, and fuzz cases for equal split, dust, and revert paths. Made-with: Cursor
Add access-control revert test, rename mock to avoid filename clash with test/mocks/, use makeAddr for labeled recipients, drop redundant mint in revert path, convert zero-amount case to a plain unit test, and add inline comments documenting invariants. Expand foundry.toml comment on the ci-profile convention. Made-with: Cursor
Contributor
|
@ivanvpan be aware there is already an I |
|
@ivanvpan you should match your format/linter to the master so you don't end up pushing many changes that are just inline params changing to stacked params. so it's easier to review the actual changes. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 1 of the fuzz-testing initiative tracked in #64. Adds a small but real fuzz harness for
EqualDistributionStrategy, wires it into CI as a parallel job, and tunes the project's default fuzz settings. No production source files are touched.What changed
test/fuzz/(new directory)EqualDistributionStrategy.t.sol— 4 tests:testFuzz_distribute_equalSplitAndDust— happy path; asserts each recipient getsamount / n, the strategy keepsamount % nas dust, anddistributionIdincrements by exactly 1.testFuzz_distribute_reverts_insufficientYield—amount < nreverts before any transfer.test_distribute_reverts_zeroAmount— zero amount reverts.testFuzz_distribute_reverts_notDistributionManager— only the configured manager can calldistribute.helpers/MockERC20.sol— minimal mintable ERC-20.helpers/MockDistManagerForFuzz.sol— minimal stub that exposesrecipientRegistry()and acts as the authorized caller.README.md— how to run, CI behavior, fork policy.foundry.toml[profile.default]now setsfuzz = { runs = 1024 }with comments noting the convention and when to revisit..github/workflows/test.ymlfuzzjob:forge test --match-path 'test/fuzz/**' -vvv(noETH_RPC_URL— these tests are fork-free).Why this scope
Existing tests cover voting, time-weighted power, registries, and cycle logic deeply, but distribution strategies and managers are mostly tested at the deploy/init level only. Phase 1 picks the smallest meaningful target on that gap: real production strategy + registry behind ERC1967 proxies, a minimal mock manager and ERC-20, no RPC fork. The intention is to land infrastructure (directory, profile, CI job) plus one well-shaped suite that future phases extend.
Dilemmas / decisions made along the way
Profile strategy (
[profile.ci]vs[profile.fuzz]vs none).FOUNDRY_PROFILE=ci, butfoundry.tomlhad no[profile.ci], so it was a no-op.[profile.fuzz]to support "deeper fuzz on demand," then reconsidered: locally is exactly where developers want more fuzzing, and adding a profile splits where fuzz settings live.[profile.default]for now (fuzz = { runs = 1024 }) and explicitly leave[profile.ci]absent. Re-evaluate onceforge testgets slow (a comment infoundry.tomlrecords the conditions to add a profile).CI placement (one job vs two).
checkjob (one compile, simpler).fuzzjob to keep the main test path identical to before fuzz work and to avoid couplingETH_RPC_URLand fork-test concerns to the fuzz path. Trade-off: a second checkout/compile, but PR latency improves with parallelism.Vendored libs.
lib/chainlink/contracts/foundry.tomletc.forge testfrom the root uses the rootfoundry.toml. Vendored libs are intentionally not modified.FOUNDRY_PROFILE: cileft in workflow.[profile.ci]).foundry.tomlexplains the no-op merge so it's not surprising.Mocks vs forks.
TestWrapperfork suites are unchanged.MockERC20directly to it instead of going manager →safeTransfer→ strategy. Documented inline so readers don't mistake it for a faithful production trace.MockDistManagerForFuzzshape.recipientRegistry_state var and an explicitrecipientRegistry()getter (two public surfaces for one value).public immutable recipientRegistry; the auto-getter matchesIDistributionManager.recipientRegistry()selector. Also renamed the file toMockDistManagerForFuzz.solto avoid filename clash withtest/mocks/MockDistributionManager.sol.What to assert.
distributionId, per-recipient share, total paid, dust, access control). Larger property suites are deferred to Phase 2/3.Plan documents not committed.
FUZZING_PLAN.mdandFUZZING_PLAN_PHASE1.mdwhile shaping this work.Test plan
Locally
forge test --match-path 'test/fuzz/**' -vv
Same command CI runs in the new job
forge test --match-path 'test/fuzz/**' -vvv