Skip to content

SIG-750: gate forge fmt, solc warnings, and slither in CI#77

Merged
worjs merged 6 commits into
mainfrom
chore/SIG-750-auto-tool-sweep
May 10, 2026
Merged

SIG-750: gate forge fmt, solc warnings, and slither in CI#77
worjs merged 6 commits into
mainfrom
chore/SIG-750-auto-tool-sweep

Conversation

@worjs
Copy link
Copy Markdown
Contributor

@worjs worjs commented May 10, 2026

Context

SIG-750. Hygiene sweep before audit kickoff: gate forge fmt --check, zero solc warnings, and slither --fail-medium in CI so audit firms see a clean baseline. Closes the last cleanup task in epic SIG-742.

Decisions

  • Solidity formatter swap: prettier-plugin-solidity removed; forge fmt is now the single source of truth for contracts/, script/, and test/. [fmt] block in foundry.toml pins line length 120, tab width 4, double quotes, no bracket spacing. package.json format and format:check scripts updated; lint-staged Solidity rule removed. Prettier still owns scripts/**/*.ts.
  • Format sweep is isolated in commit 41ca17b so reviewers can skip it and focus on the five hygiene commits that follow.
  • Slither configured (slither.config.json) with filter_paths: node_modules/|contracts/testonly/. Production detectors stay enabled. False positives use targeted slither-disable-* annotations with reasons rather than detector-level disables.
  • SignalsCoreStorage uses a single block suppression for uninitialized-state because the abstract storage container is structurally never the write site; the block comment enumerates the four lifecycle categories (initialize-then-setter, module-owned operational state, default-zero sentinels, UUPS gap).
  • ModulesUpdated unindexed-address Slither finding left in place (5 address parameters; Solidity caps indexed at 3). Documented, not changed, because indexing would be ABI-visible.
  • CI build gate uses a regex grep ^Warning \([0-9]+\): against forge build output to fail only on native solc warnings. Existing forge-lint findings remain out of scope by plan.
  • Foundry pinned to stable in CI; Slither pinned to 0.11.5.
  • Test files were not added. The only production source change is the ownerpositionOwner local rename in SignalsPosition.burn; existing position/core suites and ABI/storage diff checks cover it.

Impact

Public ABI, storage layout, and event signatures are unchanged. The only non-format production source edit is a local variable rename in SignalsPosition.burn (ownerpositionOwner); the emitted PositionBurned(positionId, positionOwner) event still uses the same indexed/non-indexed shape and value (ownerOf(positionId)).

Downstream repos (v1-subgraph, v1-sdk, v1-server, signals-app) consume ABI/events; this PR does not change either. No sibling PRs required.

Risk Areas

  • Format commit (41ca17b) touches 111 files (-3220 / +1599). It is mechanical forge fmt output, but its size obscures any non-fmt edit hidden inside. Confirm by viewing only commits 2d8e80f..HEAD for the actual hygiene changes, or by running forge fmt --check on origin/main rebased onto 41ca17b^.
  • SignalsCoreStorage Slither block suppression spans the entire storage block. Any new storage variable added inside that block silently inherits the suppression. The lifecycle comment is the contract for future writers; reviewer should confirm the four-category enumeration covers all current fields.
  • Slither annotation set on production contracts (SignalsCore, SignalsDeployer, ThetaTimeFeePolicy, ClmsrMath, LPVaultModule, MarketLifecycleModule, OracleModule, RiskModule, TradeModule, SignalsRouter). Each annotation has a justification comment; reviewer should verify the justification matches the detector and surrounding code.
  • slither.config.json filters contracts/testonly/. Anything moved out of testonly/ later is automatically re-scanned, but anything moved into testonly/ becomes invisible to Slither.
  • CI grep gate (^Warning \([0-9]+\):) is anchored to solc's current warning prefix. A solc upgrade that changes the prefix would silently disable the gate.
  • _resolvePaymentToken and the _serializeContracts operators param in DeployV1.s.sol lost their parameter names (replaced with anonymous types) to clear unused-parameter warnings. Call sites still pass the same arguments by position; verify deployment scripts that introspect parameter names (if any) are not affected.

Out of Scope

  • Forge-lint findings remain. The native solc warning gate is clean; forge-lint coverage is intentionally deferred per the SIG-750 plan.
  • Slither low/info/optimization findings remain in output but pass under --fail-medium; they are not fixed in this PR.

Copy link
Copy Markdown

@signals-reviewer signals-reviewer Bot left a comment

Choose a reason for hiding this comment

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

Summary

Hygiene-only PR that gates forge fmt --check, a solc-warning grep, and slither --fail-medium in CI before audit kickoff. Solidity formatter swaps from prettier-plugin-solidity to forge fmt (single source of truth, configured in [fmt] of foundry.toml). 10 production contracts receive targeted, justified Slither suppressions; SignalsCoreStorage gets one block-level uninitialized-state suppression with a four-category lifecycle comment. The only non-format production source change is the owner -> positionOwner local rename in SignalsPosition.burn to avoid shadowing inherited Ownable.owner() (event signature PositionBurned(uint256 indexed positionId, address indexed owner) is unchanged). DeployV1.s.sol anonymizes two unused parameters to clear unused-parameter warnings; both are confirmed unused inside their bodies and call sites pass by position.

Cross-PR Context

Sibling PRs (SIG-750)

  • Only this PR. Public ABI, event signatures, and storage layout are unchanged, so no companion PRs in v1-subgraph, v1-sdk, v1-server, or signals-app are required. Confirmed by reading the diff (no event/struct/function-signature edits) and references/impact-map.md.

Issues

No issues found.

Verification performed:

  • Position rename safety: SignalsPosition.PositionBurned event definition is event PositionBurned(uint256 indexed positionId, address indexed owner) and is unchanged. Only the local stack variable was renamed from owner to positionOwner; the indexed/non-indexed shape and emitted value (ownerOf(positionId)) are preserved. v1-subgraph only references this event in abis/SignalsCore.json (not in handler code), and the ABI is generated from the event signature, not the local variable.
  • DeployV1 unused parameters: _resolvePaymentToken's body uses only deployerKey, envName, vm.envOr, and IERC20Metadata (verified by reading the function body); deployer was dead. _writeDeployOutput's body never references the operators array (operatorAllowlist flows through params.operatorAllowlist to deployAllDeterministic instead). Both anonymizations are mechanical compile-warning fixes, not behavior changes.
  • Slither suppressions audit: Each annotation matches detector semantics and surrounding code. controlled-delegatecall on _delegateView/_riskGate is justified (modules are owner-set, dispatch design). incorrect-equality on todayBatchId == 0, openPositionCount == 0, and receivedAmount == 0 are all sentinel comparisons against natural zero values, not float-style fuzziness. divide-before-multiply + write-after-write on _toSettlementTick (both copies) is a clamp-then-snap-to-grid pattern where the floor division is the intended alignment, and the second write reads the clamped tick through offset before reassigning. uninitialized-local on cumulativeCostWad/cumulativeProceeds/totalPayout/the DeployConfig struct are all accumulators or pre-assigned structs. unused-return on applyDeposit discards mintedShares (per-depositor accounting happens at claim time, not batch time) and on computeSeedStats discards rootSum/minFactor (only deltaEt is needed for prior admissibility). reentrancy-no-eth on _initializeProxies is justified by the single-shot executed guard and trusted proxy targets.
  • SignalsCoreStorage block-level suppression: The block spans the entire storage container. Every storage variable currently inside is enumerated by category in the lifecycle comment (A: initialize-then-setter; B: module-owned operational state; C: default-zero sentinels; D: UUPS gap). The four categories cover all current fields. Risk that a future writer adds a variable inside the block silently inheriting suppression is real but documented.
  • CI gate design: ^Warning \([0-9]+\): is anchored to solc's current warning prefix. A solc upgrade that changes the prefix would silently disable the gate. Mitigation: solc is pinned to 0.8.28 in foundry.toml, foundry pinned to stable, slither pinned to 0.11.5. Storage layout, ABIs, gas snapshot, and yarn lint continue to gate other regressions.
  • Format commit isolation: Commit 41ca17b is purely forge fmt output. Verified git diff 41ca17b 2d8e80f is config-only (.prettierrc, foundry.toml, package.json, scripts/types/environment.ts, scripts/utils/release.ts, yarn.lock) with no contract source edits hidden inside.

Suggestions

None.

Verdict

APPROVE: zero unresolved items. The hygiene gates are well-scoped, the suppressions are targeted with justifications matching detector semantics and surrounding code, the format commit is mechanical and isolated, and the only production source edit (owner -> positionOwner) is an audit-friendly rename that preserves the event ABI. Risks called out in the PR description (block-level uninitialized-state suppression, solc-prefix-anchored grep gate, format-commit size) are acknowledged with reasonable mitigations for a pre-audit baseline.

@worjs worjs merged commit 1ab1bce into main May 10, 2026
12 checks passed
@worjs worjs deleted the chore/SIG-750-auto-tool-sweep branch May 10, 2026 11:54
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.

1 participant