diff --git a/docs/known-blockers.md b/docs/known-blockers.md index 34adc0f6..7e9a91f6 100644 --- a/docs/known-blockers.md +++ b/docs/known-blockers.md @@ -65,8 +65,11 @@ contributors who start from the README. default locals explicitly and have targeted regressions for string counting, delegation status/gating, empty-script rendering, and minter return indexes. - Slither high/medium findings are captured in `ops/SLITHER_BASELINE.md`; - current high/medium findings are limited to vendored-library triage and - accepted test-only helper findings before audit readiness. + current high/medium rows are now fixed, documented as false positives for + retained OpenZeppelin utility libraries, or accepted as test-only helper + findings. Vendored-library provenance is tracked in + `docs/vendored-libraries.md`. Low, informational, and optimization findings + remain outside the current CI gate. - Auction custody, auction bid/outbid payment, auction settlement-credit, fixed-price pull-payment, curator reward-credit, StreamMinter emergency-surplus, randomizer request lifecycle, randomizer callback diff --git a/docs/status.md b/docs/status.md index c4f92168..fee5d17a 100644 --- a/docs/status.md +++ b/docs/status.md @@ -13,9 +13,10 @@ The current Gate A smoke baseline proves: randomness lifecycle behavior. Current emergency-withdrawal target-state tests also cover explicit emergency recipients, `StreamMinter` surplus withdrawal, `NextGenRandomizerRNG` reserve boundaries, dependency-script - segment-safe content hashing, explicit local-initialization regressions, and - retained airdrop mint-accounting behavior after removal of dead - public/allowlist counters. + segment-safe content hashing, explicit local-initialization regressions, + vendored OpenZeppelin utility-library provenance/behavior regressions, and + retained airdrop mint-accounting behavior after removal of dead public/allowlist + counters. - Randomizer tests now cover request lifecycle views, callback validation, raw-output hash storage, failed post-processing state, bounded deterministic post-processing retry, and the conservative provider-migration policy that @@ -32,12 +33,9 @@ The current tests are regression tripwires, not a correctness proof. Known blockers remain tracked in `ops/ROADMAP.md`, including broader pull-payment accounting and cross-contract invariants, fuller randomizer reserve lifecycle accounting, callback-after-burn policy, canonical randomizer lifecycle - ownership, remaining static-analysis triage beyond the now-fixed - `uninitialized-state` mint-accounting, first-party production - `uninitialized-local`, and `weak-prng` helper rows, signer lifecycle - operations, -dependency version/freeze manifest work, deployment discipline, and the broader -P0/P1 test suite. +ownership, lower-impact static-analysis cleanup beyond the now-triaged +high/medium baseline, signer lifecycle operations, dependency version/freeze +manifest work, deployment discipline, and the broader P0/P1 test suite. Contributor and security intake files exist so future work can be packaged and reviewed consistently, but they do not change the pre-audit status. diff --git a/docs/vendored-libraries.md b/docs/vendored-libraries.md new file mode 100644 index 00000000..e8c59649 --- /dev/null +++ b/docs/vendored-libraries.md @@ -0,0 +1,50 @@ +# Vendored Libraries + +This repository currently keeps a small set of OpenZeppelin utility libraries +under `smart-contracts/` instead of importing them from a package manager. +Vendored files are allowed only when their provenance, local deltas, and +static-analysis disposition are recorded here. + +## Manifest + +| Local file | Upstream source | Upstream SHA-256 | Local SHA-256 | Local delta | +| --- | --- | --- | --- | --- | +| `smart-contracts/Base64.sol` | [OpenZeppelin Contracts v4.7.0 `contracts/utils/Base64.sol`](https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.7.0/contracts/utils/Base64.sol) | `9FBD7A4462F54BBB6B0BD03231738E5F081A092E9A8FD789FB4D1AECA3758AEC` | `3735F85C6E229E85144FBB306CD46F83BCD6965DF4705A97D06AA22F2AB8261E` | Local pragma is `^0.8.19` instead of upstream `^0.8.0`; encoding logic is unchanged. | +| `smart-contracts/Math.sol` | [OpenZeppelin Contracts v4.8.0 `contracts/utils/math/Math.sol`](https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.8.0/contracts/utils/math/Math.sol) | `8059D642EC219D0B9B62FBC76912079529CF494CAC988ABE5E371F1168B29B0F` | `D684AE61F88D564DE2D0515BC6356D0972C3CF9421F185A862D30662B7E1AD21` | Local copy keeps equivalent arithmetic with formatting deltas, an added denominator-zero comment, an overflow revert string, and `1 << (result << 3)` instead of upstream `1 << (result * 8)`. The arithmetic result is unchanged; overflow revert data differs. | +| `smart-contracts/SignedMath.sol` | [OpenZeppelin Contracts v4.8.0 `contracts/utils/math/SignedMath.sol`](https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.8.0/contracts/utils/math/SignedMath.sol) | `420A5A5D8D94611A04B39D6CF5F02492552ED4257EA82ABA3C765B1AD52F77F6` | `AEECC7E5AD0F981B63B486E2F296BB12439CA6C500FA1E62C7471AD7F72CA429` | Content matches upstream except local file ending. | +| `smart-contracts/Strings.sol` | [OpenZeppelin Contracts v4.9.0 `contracts/utils/Strings.sol`](https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.9.0/contracts/utils/Strings.sol) | `CB2DF477077A5963AB50A52768CB74EC6F32177177A78611DDBBE2C07E2D36DE` | `FD2B96FEACEA647D67A888537B75C4673C4193F444FAAE892634E5FC11C922D2` | Local imports point at sibling files in `smart-contracts/`; code behavior is otherwise unchanged. | + +## Slither Disposition + +The current high/medium Slither findings against these libraries are treated as +false positives for `P0-LIB-001`: + +- `incorrect-exp` in `Math.mulDiv(...)`: Solidity uses `^` for bitwise XOR, not + exponentiation. The expression `(3 * denominator) ^ 2` is the OpenZeppelin + modular-inverse seed used by the full-precision `mulDiv` algorithm. +- `divide-before-multiply` in `Math.mulDiv(...)`: the flagged operations are + part of the OpenZeppelin 512-bit multiplication/division algorithm and are + not lossy reorderable payment or accounting arithmetic. +- `divide-before-multiply` in `Base64.encode(...)`: the flagged length formula + intentionally computes `4 * ceil(data.length / 3)` for Base64 output sizing; + padding golden vectors cover the non-multiple-of-three cases. + +Regression coverage lives in `test/StreamVendoredLibraries.t.sol` and covers +Base64 golden vectors, binary padding, `mulDiv` full-precision boundaries, +rounding-up behavior, overflow, and zero-denominator reverts. + +## Verification Commands + +Use these commands when updating a vendored file: + +```powershell +Get-FileHash smart-contracts\Base64.sol -Algorithm SHA256 +Get-FileHash smart-contracts\Math.sol -Algorithm SHA256 +Get-FileHash smart-contracts\SignedMath.sol -Algorithm SHA256 +Get-FileHash smart-contracts\Strings.sol -Algorithm SHA256 +forge test --match-path test\StreamVendoredLibraries.t.sol -vvv +``` + +When a vendored file changes, update this manifest, rerun the focused +regressions, and refresh `ops/SLITHER_BASELINE.md` if static-analysis status or +counts change. diff --git a/ops/AUTONOMOUS_RUN.md b/ops/AUTONOMOUS_RUN.md index a7369a09..b897d190 100644 --- a/ops/AUTONOMOUS_RUN.md +++ b/ops/AUTONOMOUS_RUN.md @@ -37,7 +37,7 @@ tests, security hardening, deployment discipline, and release/audit readiness. | Last merged PR | `https://github.com/6529-Collections/6529Stream/pull/74` | | Roadmap file | `ops/ROADMAP.md` | | State file | `ops/AUTONOMOUS_RUN.md` | -| Last updated | `2026-06-10 19:30 UTC` | +| Last updated | `2026-06-10 20:01 UTC` | ## Packaging Notes @@ -87,7 +87,8 @@ The queue will evolve as PRs merge and bot feedback arrives. | 30 | Fix dependency script packed encoding | Gate C/Gate D | Implement P0-META-001 typed dependency chunk/content hashes, preserve rendered-script compatibility, add metadata encoding tests, and update Slither/roadmap traceability | Merged in PR #71 | | 31 | Remove dead mint-accounting state | Gate C | Implement P0-CORE-001 by removing never-written public/allowlist mint counters, keeping retained airdrop-counter tests, and updating Slither/roadmap traceability | Merged in PR #72 | | 32 | Remove weak helper randomness | Gate C | Implement P0-RAND-008 by removing the concrete `XRandoms` helper from production source, preserving the `RandomizerNXT` legacy-only regression, and updating Slither/roadmap traceability | Merged in PR #74 | -| 33 | Resolve first-party uninitialized locals | Gate C | Implement P0-INIT-001 by explicitly initializing remaining production locals, adding targeted regression tests, and updating Slither/roadmap traceability | Open in PR #75 | +| 33 | Resolve first-party uninitialized locals | Gate C | Implement P0-INIT-001 by explicitly initializing remaining production locals, adding targeted regression tests, and updating Slither/roadmap traceability | Merged in PR #75 | +| 34 | Prove vendored library provenance | Gate F | Complete P0-LIB-001 by documenting retained OpenZeppelin utility provenance, marking vendored Slither rows as false positives with proof, and adding focused Base64/Math regressions | In progress on `codex/prove-vendored-library-provenance` | ## Current PR Worklog @@ -2798,7 +2799,7 @@ Outcome: ### PR #75: Resolve first-party uninitialized locals (Queue Item 33) -Status: Open. +Status: Merged. Branch: `codex/resolve-uninitialized-locals`. Pull request: `#75`. Related issue: @@ -2866,6 +2867,84 @@ Validation so far: Review requests: +- CodeRabbit finished successfully on final head `b28466f`. +- Claude is intentionally skipped per current user instruction; use CodeRabbit + unless risk or future user instruction changes. + +Outcome: + +- Merged as PR #75 on `2026-06-10`. +- GitHub CI run `27301659259` passed on the final head. +- CodeRabbit status was green and both actionable review threads were marked + addressed. +- Issue #15 closed completed. + +### PR TBD: Prove vendored library provenance (Queue Item 34) + +Status: Ready to open PR. +Branch: `codex/prove-vendored-library-provenance`. +Pull request: TBD. +Related issue: + +- `https://github.com/6529-Collections/6529Stream/issues/11` + +Goal: + +- Complete `P0-LIB-001` by proving provenance for retained OpenZeppelin utility + files and resolving the remaining vendored high/medium Slither rows without + suppressing detectors. +- Add focused regressions for the exact `Base64` and `Math.mulDiv` behavior + Slither flags. +- Keep the current import layout stable; do not introduce package-manager churn + in the same PR. + +Candidate files: + +- `docs/vendored-libraries.md` +- `smart-contracts/Strings.sol` +- `test/StreamVendoredLibraries.t.sol` +- `docs/known-blockers.md` +- `docs/status.md` +- `test/README.md` +- `ops/ROADMAP.md` +- `ops/SLITHER_BASELINE.md` +- `ops/AUTONOMOUS_RUN.md` + +Implementation notes: + +- Added a vendored-library manifest with OpenZeppelin tag URLs, upstream + hashes, local hashes, and local delta notes. +- Corrected the `Strings.sol` provenance header to the v4.9.0 OpenZeppelin + content it actually matches, while keeping local sibling imports. +- Added focused Base64 golden-vector/padding tests and `Math.mulDiv` + precision, rounding, overflow, and zero-denominator tests. +- Updated Slither baseline, roadmap, status, blockers, and test README + traceability so the vendored rows are documented false positives rather than + `Needs Issue`. + +Validation so far: + +- `forge fmt --check test\StreamVendoredLibraries.t.sol` passed. +- Focused `forge test --match-path test\StreamVendoredLibraries.t.sol -vvv` + passed: 5 tests, 0 failed. +- `make check` passed on the final local head: 187 tests, 0 failed. +- `powershell -ExecutionPolicy Bypass -File scripts\check.ps1` passed on the + final local head: 187 tests, 0 failed. +- `git diff --check` passed. +- Markdown heading scan passed for the vendored-library doc, status docs, test + README, roadmap, Slither baseline, and autonomous run state. +- Traceability grep passed for `P0-LIB-001`, `StreamVendoredLibraries`, + `docs/vendored-libraries.md`, `False Positive`, `incorrect-exp`, + `divide-before-multiply`, OpenZeppelin v4.7.0/v4.8.0/v4.9.0 tags, and the + `668 total` / `4 High and 19 Medium` Slither status. +- Slither confirmation returned + `{"slither_exit":-1,"total":668,"high":4,"medium":19,"low":63,"informational":575,"optimization":7,"incorrect_exp":1,"divide_before_multiply":9,"unused_return":1}`. +- The only current `unused-return` row remains the accepted test-only + `StreamDropsERC1271Test` tuple helper; the vendored-library test adds no + high/medium Slither rows. + +Review requests: + - CodeRabbit will be requested after the PR is opened. - Claude is intentionally skipped per current user instruction; use CodeRabbit unless risk or future user instruction changes. @@ -3099,6 +3178,10 @@ Review requests: | 2026-06-10 19:20 | Select Queue Item 33 | Next focused P0 Slither blocker is `P0-INIT-001`, because explicit local initialization can eliminate remaining first-party production `uninitialized-local` rows while preserving behavior | | 2026-06-10 19:25 | Implement Queue Item 33 local draft | Initialized remaining first-party production locals explicitly, added `StreamInitialization.t.sol`, and refreshed Slither/roadmap/status/test traceability; Slither now reports one accepted test-only `uninitialized-local` row, `total=666`, `high=4`, and `medium=19` | | 2026-06-10 19:30 | Finish local Queue Item 33 validation | Focused initialization tests, full `make check`, Windows wrapper, targeted formatting, whitespace, heading scan, traceability grep, and Slither confirmation all pass; Slither final JSON has `uninitialized_local=1` test-only, `total=666`, `high=4`, and `medium=19` | +| 2026-06-10 19:46 | Merge PR #75 | First-party production uninitialized locals merged as `f042b14a43ed427fa57567d8d58a65ca2851e382`; issue #15 closed completed after CI and CodeRabbit were green | +| 2026-06-10 19:48 | Select Queue Item 34 | The only remaining non-test high/medium Slither rows are vendored OpenZeppelin utility-library findings owned by `P0-LIB-001` | +| 2026-06-10 19:55 | Implement Queue Item 34 local draft | Added vendored-library provenance docs, Base64/Math regressions, `Strings.sol` header correction, and Slither/roadmap/status/test traceability for false-positive disposition | +| 2026-06-10 20:01 | Finish local Queue Item 34 validation | Focused vendored tests, full `make check`, Windows wrapper, formatting, whitespace, heading scan, traceability grep, and Slither confirmation all pass; high/medium Slither counts remain `4 High / 19 Medium` and vendored rows are documented false positives | ## Resume Instructions diff --git a/ops/ROADMAP.md b/ops/ROADMAP.md index 16b480e0..60ae998b 100644 --- a/ops/ROADMAP.md +++ b/ops/ROADMAP.md @@ -44,7 +44,7 @@ order. | Field | Value | | --- | --- | -| Last verified | `2026-06-10 19:30 UTC` local Windows PR candidate validation; CI TBD | +| Last verified | `2026-06-10 20:01 UTC` local Windows PR candidate validation; CI TBD | | OS tested | Windows / Linux | | Foundry version | `v1.7.1` | | Solidity compiler version | `0.8.19` | @@ -57,9 +57,9 @@ order. | Area | Current status | Evidence | Required before public beta | | --- | --- | --- | --- | | Build | Passes with warnings when `forge` is invoked through the installed binary path | `forge build` | Build passes in CI and locally with warnings burned down or documented | -| Unit/integration tests | Tests cover admin guards, target-scoped function-admin permission regressions, domain-scoped pause controls, EIP-712/ERC-1271 drop authorization, auction custody and payment credits, fixed-price pull-payment credits, curator reward credits, current emergency-withdrawal boundaries, randomizer lifecycle/callback validation, randomness/pending metadata behavior, raw-output hash storage, dependency-script encoding hashes, explicit local-initialization regressions, and retained airdrop mint-accounting behavior; broader P0/P1 tests are missing | `forge test -vvv` | P0 regression and integration suite exists | +| Unit/integration tests | Tests cover admin guards, target-scoped function-admin permission regressions, domain-scoped pause controls, EIP-712/ERC-1271 drop authorization, auction custody and payment credits, fixed-price pull-payment credits, curator reward credits, current emergency-withdrawal boundaries, randomizer lifecycle/callback validation, randomness/pending metadata behavior, raw-output hash storage, dependency-script encoding hashes, explicit local-initialization regressions, vendored utility-library regressions, and retained airdrop mint-accounting behavior; broader P0/P1 tests are missing | `forge test -vvv` | P0 regression and integration suite exists | | Formatting | Fails broadly | `forge fmt --check smart-contracts` | Passing, or vendored exclusions documented | -| Static analysis | Runs with a tracked but unaccepted baseline: 666 total findings, including 4 High and 19 Medium | `slither . --config-file slither.config.json --foundry-compile-all` and `ops/SLITHER_BASELINE.md` | High/medium findings fixed, accepted, or documented | +| Static analysis | Runs with a tracked high/medium baseline: 668 total findings, including 4 High and 19 Medium; current high/medium rows are fixed, accepted, or documented false positives | `slither . --config-file slither.config.json --foundry-compile-all`, `ops/SLITHER_BASELINE.md`, and `docs/vendored-libraries.md` | High/medium findings fixed, accepted, or documented | | Deployment | Missing | no meaningful `script/`/manifest process | Anvil deployment and fork rehearsal pass | | Docs | Partial README and roadmap only | manual inspection | Architecture, security, deployment, and protocol docs merged | | Release artifacts | Missing | no ABI/address/manifest release process | ABIs, manifests, checksums, and verified addresses published | @@ -1949,8 +1949,8 @@ Current capture: - Tool: Slither `0.11.5`. - Compiler: Solidity `0.8.19`. - Command: `slither . --config-file slither.config.json --foundry-compile-all --json `. -- Status: baseline captured, not accepted as a CI gate. -- Result: 666 findings, including 4 High and 19 Medium. +- Status: high/medium rows triaged, not accepted as a CI gate. +- Result: 668 findings, including 4 High and 19 Medium. Impact summary: @@ -1959,8 +1959,8 @@ Impact summary: | High | 4 | | Medium | 19 | | Low | 63 | -| Informational | 574 | -| Optimization | 6 | +| Informational | 575 | +| Optimization | 7 | High/medium detector summary: @@ -1968,12 +1968,12 @@ High/medium detector summary: | --- | --- | ---: | --- | --- | --- | --- | | `arbitrary-send-eth` | High | 0 current / 4 fixed | first-party emergency withdrawals | Fixed | [#8](https://github.com/6529-Collections/6529Stream/issues/8) | Current emergency-withdrawal surfaces are bounded: auction, fixed-price drops, curator pool, StreamMinter surplus, and conservative randomizer reserve boundary tests now exist | | `encode-packed-collision` | High | 0 current / 3 fixed | drop authorization and dependency/script hashing | Fixed | [#9](https://github.com/6529-Collections/6529Stream/issues/9), [#10](https://github.com/6529-Collections/6529Stream/issues/10) | Drop authorization rows and dependency-script segment hashing are fixed; keep typed hash tests and Slither baseline traceability | -| `incorrect-exp` | High | 1 | vendored `Math.mulDiv` | Needs Issue | [#11](https://github.com/6529-Collections/6529Stream/issues/11) | Confirm likely false positive against pinned upstream or replace vendored library | +| `incorrect-exp` | High | 1 | vendored `Math.mulDiv` | False Positive | [#11](https://github.com/6529-Collections/6529Stream/issues/11) | OpenZeppelin provenance and `mulDiv` full-precision regressions are documented in `docs/vendored-libraries.md` and `test/StreamVendoredLibraries.t.sol` | | `reentrancy-eth` | High | 0 current / 1 fixed | auction bidding | Fixed | [#12](https://github.com/6529-Collections/6529Stream/issues/12) | Replaced bid-path push refunds with bidder pull credits and state-before-withdrawal flow | | `suicidal` | High | 3 | test-only forced-ETH helpers | Accepted | Accepted test-only | Intentionally retained for forced-ETH accounting tests under Solidity 0.8.19 | | `uninitialized-state` | High | 0 current / 2 fixed | mint-accounting mappings | Fixed | [#13](https://github.com/6529-Collections/6529Stream/issues/13) | Removed never-written public/allowlist mint-count mappings and kept retained airdrop-counter regression coverage | | `weak-prng` | High | 0 current / 2 fixed | word pool randomness helpers | Fixed | [#73](https://github.com/6529-Collections/6529Stream/issues/73) | Removed the concrete `XRandoms` production-source helper and kept `RandomizerNXT` impossible to configure for production collections | -| `divide-before-multiply` | Medium | 9 | vendored math/base64 helpers | Needs Issue | [#11](https://github.com/6529-Collections/6529Stream/issues/11) | Confirm likely false positive against pinned upstream or replace vendored library | +| `divide-before-multiply` | Medium | 9 | vendored math/base64 helpers | False Positive | [#11](https://github.com/6529-Collections/6529Stream/issues/11) | OpenZeppelin provenance plus Base64 padding and `mulDiv` precision regressions are documented in `docs/vendored-libraries.md` and `test/StreamVendoredLibraries.t.sol` | | `incorrect-equality` | Medium | 1 | test-only malleable-signature helper | Accepted | Accepted test-only | Keep scoped to test-only EIP-712 negative coverage | | `locked-ether` | Medium | 7 | test-only rejection/reentrancy/mock receivers | Accepted | Accepted test-only | Keep scoped to payment and emergency-withdrawal tests | | `uninitialized-local` | Medium | 1 current accepted test-only / 11 fixed | first-party and test helper locals | Fixed for first-party production rows; only the accepted test-only `MockStreamMinter` helper row remains current | [#15](https://github.com/6529-Collections/6529Stream/issues/15), [#9](https://github.com/6529-Collections/6529Stream/issues/9) | Keep production locals explicit and test-only acceptance documented | @@ -2020,6 +2020,7 @@ Status values: `Missing`, `Planned`, `In Progress`, `Passing`, `Blocked`. | Deployment redeployment rehearsal | Deployment manifests, ABI hashes, admin ceremony, signer setup, deprecation checks, and emergency redeployment rehearsal follow ADR 0007 | `test/StreamDeploymentManifest.t.sol` and `script/RehearseDeployment.s.sol` | Missing | [`P2-UPGRADE-ADR`](https://github.com/6529-Collections/6529Stream/issues/53) | Gate E/Gate G | TBD | | Mint-accounting state | Dead counters are removed or retained counters initialize and update according to the accepted drop/mint accounting design | `test/StreamMintAccounting.t.sol` | Passing: removed never-written public/allowlist mint-count mappings and retrieval APIs; retained airdrop counter starts at zero, increments on authorized minter calls, and remains unchanged on unauthorized mint attempts | [`P0-CORE-001`](https://github.com/6529-Collections/6529Stream/issues/13) | Gate C | TBD | | Uninitialized local findings | First-party default-local behavior is explicit, removed, or covered by targeted regressions | `test/StreamInitialization.t.sol` | Passing: Bytes32 character counts, missing/matching delegation lookups, subdelegation register/revoke gates, empty-script generative rendering, and multi-recipient minter return indexes cover the remaining first-party production rows; Slither now reports only one accepted test-only `uninitialized-local` row | [`P0-INIT-001`](https://github.com/6529-Collections/6529Stream/issues/15) | Gate C | TBD | +| Vendored library Slither findings | Retained OpenZeppelin utility files have provenance, local delta notes, and regressions for flagged math/encoding behavior | `test/StreamVendoredLibraries.t.sol` | Passing: Base64 golden/padding vectors, `Math.mulDiv` full-precision boundaries, rounding-up behavior, overflow, and zero-denominator reverts cover the current vendored false-positive rows | [`P0-LIB-001`](https://github.com/6529-Collections/6529Stream/issues/11) | Gate F | TBD | | Curator double claim | Valid claim succeeds once and second claim fails | `test/StreamCuratorsPool.t.sol` | Passing for P0-PAY-005: valid claims create credits and duplicate claims fail without increasing credit | [`P0-PAY-005`](https://github.com/6529-Collections/6529Stream/issues/29) | Gate C/Gate D | TBD | | Merkle leaf ambiguity | Duplicate or ambiguous leaves cannot double claim | `test/StreamCuratorsPool.t.sol` | In Progress: reward leaves use `abi.encode`-based hashing for reward address, collection ID, and amount; root epoch/domain expansion remains future curator metadata work | [`P0-PAY-005`](https://github.com/6529-Collections/6529Stream/issues/29), `P1-CURATOR-*` | Gate D | TBD | | Burn accounting | Burned-token supply, unavailable `tokenURI`, retained audit state, and callback-after-burn behavior follow ADR 0006 | `test/StreamCoreBurn.t.sol` | Missing | [`P1-META-ADR`](https://github.com/6529-Collections/6529Stream/issues/45), [`P1-META-005`](https://github.com/6529-Collections/6529Stream/issues/50), [`P0-RAND-004`](https://github.com/6529-Collections/6529Stream/issues/40) | Gate D | TBD | diff --git a/ops/SLITHER_BASELINE.md b/ops/SLITHER_BASELINE.md index 2d485f2b..4a9d5172 100644 --- a/ops/SLITHER_BASELINE.md +++ b/ops/SLITHER_BASELINE.md @@ -1,14 +1,15 @@ # Slither Baseline -This is the tracked high/medium Slither baseline for 6529Stream. It is a triage -input, not an accepted security baseline. +This is the tracked high/medium Slither baseline for 6529Stream. High and +medium rows are fixed, accepted with rationale, or documented as false +positive; this is still not a full security baseline for public launch. ## Capture Metadata | Field | Value | | --- | --- | -| Status | Open baseline; not accepted as a CI gate | -| Last generated | `2026-06-10 19:30 UTC` | +| Status | High/medium rows triaged; not accepted as a CI gate | +| Last generated | `2026-06-10 20:01 UTC` | | Slither | `0.11.5` | | Solidity compiler | `0.8.19` | | solc-select | `1.2.0` | @@ -17,7 +18,7 @@ input, not an accepted security baseline. Slither returned detector results successfully, but the process exited non-zero because findings exist. That is expected until the roadmap accepts a gated -baseline. +baseline and lower-impact findings are handled. ## Impact Counts @@ -26,9 +27,9 @@ baseline. | High | 4 | | Medium | 19 | | Low | 63 | -| Informational | 574 | -| Optimization | 6 | -| Total | 666 | +| Informational | 575 | +| Optimization | 7 | +| Total | 668 | ## Detector Counts @@ -45,8 +46,8 @@ baseline. | `uninitialized-local` | Medium | 1 | | `unused-return` | Medium | 1 | | Low-impact findings | Low | 63 | -| Informational findings | Informational | 574 | -| Optimization findings | Optimization | 6 | +| Informational findings | Informational | 575 | +| Optimization findings | Optimization | 7 | Dependency-script encoding delta from the previous tracked capture: @@ -81,10 +82,17 @@ Dependency-script encoding delta from the previous tracked capture: cleanup. - `uninitialized-local` now has one current finding, and it is the accepted test-only `MockStreamMinter.mint(...).mintedCount` row. +- Vendored-library provenance delta from the previous tracked capture: + - High and Medium counts remain unchanged at 4 and 19. + - Informational findings increased from 574 to 575 and Optimization findings + increased from 6 to 7 after adding the provenance test harness and + correcting the `Strings.sol` upstream header. + - The current vendored `incorrect-exp` and `divide-before-multiply` rows are + documented false positives, not open remediation items. - `arbitrary-send-eth` and `reentrancy-eth` remain at zero findings. -- Slither still exits non-zero because the remaining tracked baseline findings - require fixes, accepted-risk rationale, or false-positive proof before audit - readiness. +- Slither still exits non-zero because accepted test-only and vendored + false-positive rows remain visible, plus lower-impact findings are not yet a + CI gate. ## Status Semantics @@ -111,15 +119,15 @@ GitHub work item that owns that resolution. | `encode-packed-collision` | 1 | `StreamCore` | `retrieveDependencyScript(uint256)` | first-party | Fixed in `P0-META-001` | High | High | Fixed | Replaced packed dynamic dependency-script composition with initialized `string.concat` rendering and typed dependency chunk/content hash views that use `abi.encode`, dependency key, chunk count, chunk index, chunk byte length, and per-chunk content hash | Ambiguous chunk-boundary and typed hash regressions in `test/StreamMetadataEncoding.t.sol` | [`P0-META-001`](https://github.com/6529-Collections/6529Stream/issues/9) | Gate C | TBD | | `encode-packed-collision` | 1 | `StreamDrops` | `retrieveMessageAndDropID(address,address,string,uint256,uint256,uint256,uint256)` | first-party | Removed in `P0-AUTH-002` | High | High | Fixed | Removed legacy packed helper; `hashDropAuthorization` now uses EIP-712 domain-separated typed data | Explicit digest, replay, wrong-domain, wrong-chain, wrong-contract, and field-substitution tests in `test/StreamDropsEIP712.t.sol` | [`P0-AUTH-002`](https://github.com/6529-Collections/6529Stream/issues/10) | Gate C | TBD | | `encode-packed-collision` | 1 | `StreamDrops` | `mintDrop(address,address,string,uint256,uint256,uint256,uint256)` | first-party | Removed in `P0-AUTH-002` | High | High | Fixed | Replaced legacy packed-hash `mintDrop` ABI with `mintDrop(DropAuthorization,string,bytes)` and storage-backed consumed/cancelled drop IDs | EOA, EIP-2098, replay, expiry, cancellation, stale-epoch, wrong-domain, wrong-chain, wrong-contract, wrong-signer, malleability, zero signer, bad quantity, and token-substitution tests in `test/StreamDropsEIP712.t.sol` | [`P0-AUTH-002`](https://github.com/6529-Collections/6529Stream/issues/10) | Gate C | TBD | -| `incorrect-exp` | 1 | `Math` | `mulDiv(uint256,uint256,uint256)` | vendored | `smart-contracts/Math.sol#L55-L134` | High | Medium | Needs Issue | Likely false positive; confirm against pinned upstream OpenZeppelin or replace retained library with package-managed upstream before acceptance | Library provenance or math regression | [`P0-LIB-001`](https://github.com/6529-Collections/6529Stream/issues/11) | Gate F | TBD | +| `incorrect-exp` | 1 | `Math` | `mulDiv(uint256,uint256,uint256)` | vendored | `smart-contracts/Math.sol#L55-L134` | High | Medium | False Positive | `Math.sol` is tracked to OpenZeppelin Contracts v4.8.0 in `docs/vendored-libraries.md`; `(3 * denominator) ^ 2` is the intended bitwise-XOR seed for modular inverse calculation, not exponentiation | `test/StreamVendoredLibraries.t.sol::testMathMulDivHandlesFullPrecisionBoundaries`; `testMathMulDivRevertsForOverflowAndZeroDenominator` | [`P0-LIB-001`](https://github.com/6529-Collections/6529Stream/issues/11) | Gate F | TBD | | `suicidal` | 3 | Forced-ETH test helpers | `force(address)` | test-only | `test/StreamAuctionPayments.t.sol`, `test/StreamCuratorsPool.t.sol`, `test/StreamFixedPricePayments.t.sol` | High | Medium | Accepted | Accepted as intentional Solidity 0.8.19 `selfdestruct` helpers used only to test forced-ETH surplus accounting | Forced-ETH tests in the owning files | Accepted test-only | Gate A | TBD | | `reentrancy-eth` | 1 | `StreamAuctions` | `participateToAuction(uint256)` | first-party | Fixed in `P0-AUCT-002` | High | Medium | Fixed | Replaced synchronous outbid refund `call` with bidder credit accounting; highest-bid state and auction escrow accounting update before any external withdrawal path | `test/StreamAuctionPayments.t.sol` | [`P0-AUCT-002`](https://github.com/6529-Collections/6529Stream/issues/12) | Gate C | TBD | | `uninitialized-state` | 1 | `StreamCore` | `state variable tokensMintedPerAddress` | first-party | Removed in `P0-CORE-001` | High | High | Fixed | Removed the never-written public-sale mint-count mapping and retrieval API instead of exposing an always-zero counter with no accepted quota semantics | Retained airdrop-counter regression in `test/StreamMintAccounting.t.sol` | [`P0-CORE-001`](https://github.com/6529-Collections/6529Stream/issues/13) | Gate C | TBD | | `uninitialized-state` | 1 | `StreamCore` | `state variable tokensMintedAllowlistAddress` | first-party | Removed in `P0-CORE-001` | High | High | Fixed | Removed the never-written allowlist mint-count mapping and retrieval API because the current drop path has no allowlist phase semantics | Retained airdrop-counter regression in `test/StreamMintAccounting.t.sol` | [`P0-CORE-001`](https://github.com/6529-Collections/6529Stream/issues/13) | Gate C | TBD | | `weak-prng` | 1 | `randomPool` | `randomNumber()` | first-party | Removed in `P0-RAND-008` | High | Medium | Fixed | Removed the concrete production-source `XRandoms` helper contract instead of shipping block-derived helper randomness alongside production randomizer adapters | `test/StreamRandomizerLifecycle.t.sol::testNxtRandomizerCannotBeConfiguredForProductionCollections` plus Slither `weak-prng=0` confirmation | [`P0-RAND-008`](https://github.com/6529-Collections/6529Stream/issues/73) | Gate C | TBD | | `weak-prng` | 1 | `randomPool` | `randomWord()` | first-party | Removed in `P0-RAND-008` | High | Medium | Fixed | Removed the concrete production-source `XRandoms` helper contract instead of shipping block-derived helper randomness alongside production randomizer adapters | `test/StreamRandomizerLifecycle.t.sol::testNxtRandomizerCannotBeConfiguredForProductionCollections` plus Slither `weak-prng=0` confirmation | [`P0-RAND-008`](https://github.com/6529-Collections/6529Stream/issues/73) | Gate C | TBD | -| `divide-before-multiply` | 1 | `Base64` | `encode(bytes)` | vendored | `smart-contracts/Base64.sol#L20-L91` | Medium | Medium | Needs Issue | Likely false positive; confirm against pinned upstream OpenZeppelin or replace retained library with package-managed upstream before acceptance | Library provenance or precision regression | [`P0-LIB-001`](https://github.com/6529-Collections/6529Stream/issues/11) | Gate F | TBD | -| `divide-before-multiply` | 8 | `Math` | `mulDiv(uint256,uint256,uint256)` | vendored | `smart-contracts/Math.sol#L55-L134` | Medium | Medium | Needs Issue | Likely false positive; confirm against pinned upstream OpenZeppelin or replace retained library with package-managed upstream before acceptance | Library provenance or precision regression | [`P0-LIB-001`](https://github.com/6529-Collections/6529Stream/issues/11) | Gate F | TBD | +| `divide-before-multiply` | 1 | `Base64` | `encode(bytes)` | vendored | `smart-contracts/Base64.sol#L20-L91` | Medium | Medium | False Positive | `Base64.sol` is tracked to OpenZeppelin Contracts v4.7.0 in `docs/vendored-libraries.md`; the flagged expression intentionally computes Base64 output length as `4 * ceil(data.length / 3)` | `test/StreamVendoredLibraries.t.sol::testBase64EncodingMatchesOpenZeppelinGoldenVectors`; `testBase64EncodingPreservesBinaryInputsAndPadding` | [`P0-LIB-001`](https://github.com/6529-Collections/6529Stream/issues/11) | Gate F | TBD | +| `divide-before-multiply` | 8 | `Math` | `mulDiv(uint256,uint256,uint256)` | vendored | `smart-contracts/Math.sol#L55-L134` | Medium | Medium | False Positive | `Math.sol` is tracked to OpenZeppelin Contracts v4.8.0 in `docs/vendored-libraries.md`; the flagged operations are part of the full-precision 512-bit `mulDiv` algorithm and are not lossy protocol accounting arithmetic | `test/StreamVendoredLibraries.t.sol::testMathMulDivHandlesFullPrecisionBoundaries`; `testMathMulDivRoundingUpOnlyIncrementsOnRemainder` | [`P0-LIB-001`](https://github.com/6529-Collections/6529Stream/issues/11) | Gate F | TBD | | `incorrect-equality` | 1 | `DropAuthTestHelper` | `signMalleableAuthorization(...)` | test-only | `test/helpers/DropAuthTestHelper.sol#L113-L123` | Medium | Medium | Accepted | Accepted as a test-only helper branch used to manufacture malleable signatures for negative authorization tests | `test/StreamDropsEIP712.t.sol` malleability tests | Accepted test-only | Gate A | TBD | | `locked-ether` | 7 | Rejection/reentrancy/mock receivers | payable test helpers | test-only | `test/StreamAuctionPayments.t.sol`, `test/StreamCuratorsPool.t.sol`, `test/StreamEmergencyWithdraw.t.sol`, `test/StreamFixedPricePayments.t.sol`, `test/mocks/MockRandomizer.sol` | Medium | High | Accepted | Accepted as test-only receivers and mocks used to characterize failed transfers, reentrancy attempts, and randomizer provider payments | Payment and emergency-withdrawal tests in the owning files | Accepted test-only | Gate A | TBD | | `uninitialized-local` | 1 | `Bytes32Strings` | `containsExactCharacterQty(...)._occurrences` | first-party | Fixed in `P0-INIT-001` | Medium | Medium | Fixed | Initialized the occurrence counter to zero before scanning the bytes32 source | `test/StreamInitialization.t.sol::testBytes32CharacterCountingUsesExplicitZeroStart` | [`P0-INIT-001`](https://github.com/6529-Collections/6529Stream/issues/15) | Gate C | TBD | @@ -150,7 +158,8 @@ backed by a regression test or accepted-risk rationale. - Fix first-party high findings before any public beta claim. - Convert each fixed finding into a regression test in the test matrix. - Replace retained upstream libraries with pinned upstream packages or document - provenance before accepting vendored library rows. + provenance before accepting vendored library rows. The current retained + OpenZeppelin utility files are documented in `docs/vendored-libraries.md`. - Keep every `Needs Issue` row linked to a GitHub issue before accepting or suppressing it. - Do not suppress a detector until the finding or scoped suppression is diff --git a/smart-contracts/Strings.sol b/smart-contracts/Strings.sol index eda4eba7..0e2a914a 100644 --- a/smart-contracts/Strings.sol +++ b/smart-contracts/Strings.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; @@ -83,4 +83,4 @@ library Strings { function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } -} \ No newline at end of file +} diff --git a/test/README.md b/test/README.md index 8a33dd0b..57e30feb 100644 --- a/test/README.md +++ b/test/README.md @@ -140,3 +140,9 @@ Explicit local initialization now has P0-INIT-001 target-state coverage in delegation status lookups, subdelegation register/revoke gates, empty-script generative rendering, and multi-recipient minter return indexes cover the former first-party production `uninitialized-local` rows. + +Vendored library provenance now has P0-LIB-001 coverage in +`StreamVendoredLibraries.t.sol`: Base64 golden vectors, binary padding, +`Math.mulDiv` full-precision boundaries, rounding-up behavior, overflow, and +zero-denominator reverts cover the OpenZeppelin utility-library rows documented +as false positives in `docs/vendored-libraries.md` and `ops/SLITHER_BASELINE.md`. diff --git a/test/StreamVendoredLibraries.t.sol b/test/StreamVendoredLibraries.t.sol new file mode 100644 index 00000000..db0e1d5d --- /dev/null +++ b/test/StreamVendoredLibraries.t.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import "../smart-contracts/Base64.sol"; +import "../smart-contracts/Math.sol"; +import "./helpers/Assertions.sol"; + +contract VendoredLibraryHarness { + function encode(bytes memory data) external pure returns (string memory) { + return Base64.encode(data); + } + + function mulDiv(uint256 x, uint256 y, uint256 denominator) external pure returns (uint256) { + return Math.mulDiv(x, y, denominator); + } + + function mulDivUp(uint256 x, uint256 y, uint256 denominator) external pure returns (uint256) { + return Math.mulDiv(x, y, denominator, Math.Rounding.Up); + } +} + +contract StreamVendoredLibrariesTest { + using Assertions for bool; + using Assertions for bytes32; + using Assertions for string; + using Assertions for uint256; + + VendoredLibraryHarness private harness = new VendoredLibraryHarness(); + + function testBase64EncodingMatchesOpenZeppelinGoldenVectors() public view { + harness.encode("").assertEq("", "empty base64"); + harness.encode(bytes("f")).assertEq("Zg==", "one-byte base64"); + harness.encode(bytes("fo")).assertEq("Zm8=", "two-byte base64"); + harness.encode(bytes("foo")).assertEq("Zm9v", "three-byte base64"); + harness.encode(bytes("foob")).assertEq("Zm9vYg==", "four-byte base64"); + harness.encode(bytes("fooba")).assertEq("Zm9vYmE=", "five-byte base64"); + harness.encode(bytes("foobar")).assertEq("Zm9vYmFy", "six-byte base64"); + } + + function testBase64EncodingPreservesBinaryInputsAndPadding() public view { + bytes memory zeroOneTwo = hex"000102"; + bytes memory allOnes = hex"ffffff"; + bytes memory withPadding = hex"0001"; + + harness.encode(zeroOneTwo).assertEq("AAEC", "binary base64"); + harness.encode(allOnes).assertEq("////", "all ones base64"); + harness.encode(withPadding).assertEq("AAE=", "binary padding base64"); + } + + function testMathMulDivHandlesFullPrecisionBoundaries() public view { + harness.mulDiv(type(uint256).max, type(uint256).max, type(uint256).max) + .assertEq(type(uint256).max, "max exact mulDiv"); + harness.mulDiv(type(uint256).max, 2, type(uint256).max) + .assertEq(2, "full precision quotient"); + harness.mulDiv(5, 5, 2).assertEq(12, "floor rounding"); + } + + function testMathMulDivRoundingUpOnlyIncrementsOnRemainder() public view { + harness.mulDivUp(5, 5, 2).assertEq(13, "rounding remainder"); + harness.mulDivUp(10, 10, 5).assertEq(20, "rounding exact"); + } + + function testMathMulDivRevertsForOverflowAndZeroDenominator() public view { + (bool overflowSuccess, bytes memory overflowRevertData) = address(harness) + .staticcall( + abi.encodeWithSelector( + harness.mulDiv.selector, type(uint256).max, type(uint256).max, 1 + ) + ); + overflowSuccess.assertFalse("overflow mulDiv succeeded"); + keccak256(overflowRevertData) + .assertEq( + keccak256(abi.encodeWithSignature("Error(string)", "Math: mulDiv overflow")), + "overflow revert data" + ); + + (bool zeroDenominatorSuccess, bytes memory zeroDenominatorRevertData) = + address(harness).staticcall(abi.encodeWithSelector(harness.mulDiv.selector, 1, 1, 0)); + zeroDenominatorSuccess.assertFalse("zero denominator mulDiv succeeded"); + keccak256(zeroDenominatorRevertData) + .assertEq( + keccak256(abi.encodeWithSignature("Panic(uint256)", 0x12)), + "zero denominator revert data" + ); + } +}