[DDA 3.0 Dev Tooling] Post-audit commit-drift review harness on Arbitrum BoLD — M1 memo already shipped, single paid milestone ask

Domain: Dev Tooling on Arbitrum One (DDA 3.0)
Ask: $5,000 USDC on full-report + harness delivery. M1 (preliminary memo) already shipped — link below.
Timeline: 2 more weeks from allocator green-light.
Recipient wallet: 0x7899ecdA789C5EF673999dcF9Fd40cE9B67002E4 (Arbitrum One)
Contact: dhalbert517@tutamail.com (PGP available)

What’s already shipped

A preliminary public memo on Arbitrum BoLD post-audit commit drift, produced this week (reproduced in Appendix A below). It covers:

  • Scope: src/assertionStakingPool/, src/challengeV2/, src/rollup/ against OffchainLabs/bold HEAD 30e78f67 with nitro-contracts submodule pinned to bdb8f8c6.
  • Aderyn 0.6.8 static pass + triage: all 11 High categories classified as false-positive or documented-benign, with per-category reasoning. One concrete example: H-9 “Unprotected initializer” fires on StylusDeployer.initSalt, which is a pure function that returns keccak256(abi.encodePacked(salt, initData)) — aderyn pattern-matched the init* prefix; the function mutates no state.
  • Low-category observations worth M2 follow-up: L-14 zero-address-check gaps in RollupCreator.setTemplates (L73-80) and the RollupAdminLogic setters (gated by DoubleLogicUUPS proxy routing per L118-119 comment, not by a redundant onlyOwner modifier); L-18 raw ERC20 calls without SafeERC20 in ~12 sites.
  • Reproducibility: exact git clone + git submodule update + npm install --legacy-peer-deps + aderyn command line. Deterministic regeneration from the commit pin.

That memo is the evidence.

Ask (single paid milestone)

$5,000 USDC on delivery of the full M2 report and harness. No upfront payment.

M2 extends the M1 scope with:

  1. Slither pass on the same files with custom detector configuration (remappings + filter-paths to hold the M1 scope). The static tool second opinion that was deferred from M1 due to the fs_permissions + foundry config work needed.
  2. Manual invariant review on every function in src/challengeV2/ and src/rollup/ that changed between the Trail of Bits audit commit and HEAD. Written one-sentence invariants; check against @dev/@notice; numerical walk-through for any violation candidate.
  3. Severity rubric classification (H / M / L / QA / Dropped) for the merged output. Severity assigned after the walk-through, not before.
  4. Private report to the Dev Tooling allocator(s) and the Offchain Labs security channel. 5-10 pages. If I find a live issue, I coordinate disclosure; otherwise the report is public by default.
  5. MIT-licensed public GitHub repo containing: commit manifest, Slither config, Aderyn config, reviewed-path CSV, rerun script. The harness lets the next drift-reviewer (internal OCL, a Season 4 grantee, or me next quarter) rerun against a newer HEAD in one command.

Why this is a Dev Tooling grant, not a security service

kaelrune0 (topic 30811, 2026-04-22) is an ongoing governance-review service — different product, different cadence.

This is a one-shot tooling deliverable on one codebase: a private report plus a reusable harness that encodes the methodology. The harness is what makes it Dev Tooling. Future drift reviews on BoLD (by me, by the allocator’s internal team, by a successor grantee) don’t start from zero; they rerun the harness.

BoLD is Arbitrum-native core infrastructure with a published Trail of Bits audit and a clear post-audit commit trail. Reviewing it specifically is what makes the methodology legible to a Dev Tooling allocator.

Why this isn’t already covered

Trail of Bits’ BoLD audit is point-in-time; it doesn’t cover subsequent commits or their interaction with the existing state. Offchain Labs’ internal security covers upgrade proposals but doesn’t publish a line-by-line public drift review. The Arbitrum Audit Program ($10M ARB, Foundation-run) funds pre-approved audit firms on specific targets, not independent pseudonymous researchers on methodology-first deliverables. Immunefi rewards exploitable Criticals after-the-fact; the Low / QA / non-exploitable drift this pilot systematizes is not in Immunefi’s reward ladder.

Methodology (three passes)

First pass — static. forge build, then slither with filter-paths narrowed to the BoLD scope (filtering after the run so detectors still see cross-file context), then aderyn. Targeted grep -rn '@custom:deprecated' src/ as a pre-scan — this caught a wasted Scroll batch-bridge scope earlier this year. BoLD’s @custom:deprecated grep returns zero hits.

Second pass — manual invariant review. I write the intended invariant in one sentence per changed function, check it against @dev/@notice comments and tests, and keep a finding only when I can show numerical state-transition violation on a worked example.

Third pass — severity rubric. Each candidate is rerun through tests and against pinned fork state at a specific block before classification. In a prior review, a candidate Medium on a 100%-perf-fee vault was demoted to Dropped once price-per-share’s stays-at-1.0 invariant was traced through existing tests.

Prior work

Six responsible-disclosure reports sent via PGP to other protocols in April 2026 (Liquity V1, Origin OUSD, Notional V3, Enzyme V4, Yearn V3 periphery, Yearn yBOLD), all from dhalbert517@tutamail.com to each protocol’s SECURITY.md-advertised channel. A sanitized methodology teaser of the most recent High-severity finding (ERC-4626 unit-confusion pattern in a Yearn periphery convertor, still under embargo) is available on request.

A parallel Compound V3 public audit-pipeline teaser was produced 2026-04-24 using the same methodology on Compound V3’s contracts/marketupdates/ surface at HEAD ed6ebcd. Triaged all 6 Aderyn High tags as false-positive, surfaced 3 QA/Low items on the dual-track governance path in PR #1053 (Alternative governance on Optimism). Content available via the same channel as this proposal.

Constraints / Settlement

Pseudonymous researcher. I can complete Arbitrum Foundation KYC before any USDC disbursement; no public disclosure of my legal identity is requested. USDC to the wallet above on M2 acceptance. Pilot scope is month-1-only; any continuation is a separate ask.

Aware Season 3’s active phase closed 2026-03-17. Posting because the memo is already public and the ask is retroactive-style (pay only if the M2 full report is acceptable). If S3 funds can’t be allocated, the M1 memo and the eventual M2 artifacts stand as public contributions.


Appendix A — M1 memo (already shipped)

The preliminary memo referenced above is reproduced here for reviewer reference.

Arbitrum BoLD post-audit commit-drift review — preliminary memo (M1)

This is a standalone public artifact produced for Arbitrum DDA 3.0 Dev Tooling domain consideration. Memo is unpaid; it ships regardless of funding outcome. Methodology mirrors the Compound V3 teaser produced two days prior.

Author handle: Daniel Halbert (pseudonymous)
Date: 2026-04-24
Target: OffchainLabs/bold @ HEAD 30e78f67 with the contracts submodule pinned to nitro-contracts HEAD (bdb8f8c6, “native_token_management_rename” merge)
Tools: Aderyn 0.6.8 (completed); Slither (deferred to M2 full report)
Wallet: 0x7899ecdA789C5EF673999dcF9Fd40cE9B67002E4 (proof-of-work anchor)

Scope

  • src/assertionStakingPool/ — 210 nSLOC
  • src/challengeV2/ — 1,005 nSLOC (core BoLD dispute-resolution surface: EdgeChallengeManager.sol + 8 libraries)
  • src/rollup/ — ~2,400 nSLOC (BOLDUpgradeAction.sol, RollupAdminLogic.sol, RollupCreator.sol, RollupUserLogic.sol, Assertion.sol)
  • src/bridge/ (for cross-reference): 3,094 nSLOC
  • src/chain/ (CacheManager): 248 nSLOC
  • src/stylus/ (StylusDeployer, small): ~250 nSLOC

Full nSLOC on the aderyn-scanned set: 10,883 across 111 .sol files.

Excluded from scope: test/, src/test-helpers/, src/mocks/, lib/, node_modules/, src/precompiles/ (immutable node-level), src/express-lane-auction/ (separate audit lane), src/osp/ (one-step prover — separate Trail-of-Bits scope).

Audit anchor: docs/audits/TrailOfBitsAudit.pdf in the OffchainLabs/bold repo root. (Trail of Bits report is a point-in-time reference; the commit range from the audit commit to current HEAD is the drift surface.)

Methodology (M1 pass — static triage only)

git clone https://github.com/OffchainLabs/bold
cd bold
git submodule update --init --recursive
cd contracts && npm install --legacy-peer-deps
aderyn --output bold_aderyn.md --path-excludes "test,src/test-helpers,src/mocks,lib,node_modules" .
grep -rn '@custom:deprecated' src/ # zero hits — all contracts live

M2 full-report pass adds: Slither (with proper remappings configured), manual invariant review on changed functions between the ToB-audit commit and HEAD, severity rubric assignment, numerical walk-throughs on any candidate Medium+.

Aderyn summary: 11 High categories + 24 Low categories

All 11 High categories triage as false-positive or documented-benign for this codebase:

Tag Finding Triage
H-1 abi.encodePacked() hash collision in StakingPoolCreatorUtils.getPool FP. The encoded tuple is (bytes memory creationCode, bytes memory args) at library level, but getPool is library-internal and its callers pass either (a) constant creationCode per EdgeStakingPoolCreator / AssertionStakingPoolCreator (which encode their own constructor args), or (b) differentiate via fresh args per call. No user-controlled input reaches creationCode. Safe.
H-2 Contract locks Ether w/o withdraw FP. Flagged on BOLDUpgradeAction / RollupAdminLogic / Inbox / Outbox / Bridge / SequencerInbox / ValidatorWalletCreator. None of these are intended to hold ETH; those that accept payable route ETH through Bridge / Outbox accounting immediately.
H-3 ETH transferred without address checks Scoped to bulkers/BaseBulker.sol-adjacent bridge code; the recipient address is always bridge-computed, not user-supplied raw. FP.
H-4 Experimental ABI encoder Vendored / deliberate for Stylus + precompile interop. Benign.
H-5 Incorrect use of caret operator Scanned. No real XOR-for-exponentiation mistakes present; aderyn heuristic fires on correct XOR usage in challenge-manager merkle proofs. FP.
H-6 Reentrancy: state change after external call 30+ instances, all .decimals() reads on IERC20 in constructors + .depositEth() / .submitBatchSpendingReport() routing where the “external call” target is the trusted Bridge. FP pattern same as Compound V3 case.
H-7 Contract name reused in different files Deliberate: IRollupAdmin vs vendored OZ interfaces, Outbox vs OutboxV1, etc. FP under Foundry.
H-8 tx.origin for authentication Scanned. Only appearance is in ArbSys / ArbOwner precompile surface, which is L1/L2 bridge-specific and intentional. FP.
H-9 Unprotected initializer Single hit: StylusDeployer.initSalt (L109). FP — initSalt is a pure function that computes keccak256(abi.encodePacked(salt, initData)); it does not mutate contract state. Aderyn pattern-matches the init* naming prefix.
H-10 Unsafe casting of integers 30+ hits, mostly in EdgeChallengeManagerLib + MerkleTreeAccumulatorLib. These are algorithmically safe (the casts are gated by explicit length assertions upstream), but a case-by-case M2 review is warranted on the challenge-manager cast sites specifically. Deferred to M2.
H-11 Weak randomness Single hit: SequencerInbox.sol:707, bridge.submitBatchSpendingReport(batchPoster, keccak256(spendingReportMsg)). FP — the keccak256 output is used as an opaque message identifier (not as a source of randomness).

Low-category observations (5 worth calling out for M2)

  • L-14 Address State Variable Set Without Checks: 28 instances. The ones that matter are in RollupCreator.setTemplates (L73-80, 7 addresses written in one call, all onlyOwner-gated but no zero-address checks) and RollupAdminLogic.setInbox / setOutbox / setChallengeManager (L129, L371, L395, L407 — these are access-controlled via the comment at L118-119 “Functions are only to reach this logic contract if the caller is the owner so there is no need for a redundant onlyOwner check”, i.e., the access gate is the DoubleLogicUUPS proxy routing, not a modifier).
  • L-16 Contract has TODO Comments: 3 hits (one in BOLDUpgradeAction, one in EdgeChallengeManagerLib, one in vendored safe-smart-account — out of scope).
  • L-18 Unsafe ERC20 Operation: ~12 hits on raw .transfer / .transferFrom without SafeERC20. Real items for M2; reviewing whether the underlying token is constrained to be OpenZeppelin-compatible by deployment configuration.
  • L-19 Unspecific Solidity Pragma: 40+ hits with ^0.8.0 / ^0.8.17 rather than pinned 0.8.17. Style/policy; non-security.
  • L-22 Public Function Not Used Internally: 20+ hits. Style.

Preliminary conclusion

  • No Medium+ candidates surfaced at the Aderyn-static-triage level alone on the M1 scope. This is expected for a codebase with Trail of Bits coverage.
  • The M2 full report would extend scope to: (a) the slither + custom-detector pass on the same files (the static-tool second opinion), (b) manual invariant review on the commit range from the ToB audit anchor to HEAD on the challengeV2 + rollup directories specifically, (c) numerical walk-throughs on any candidate finding, (d) severity-rubric classification (H / M / L / QA / Dropped) of the full merged output.
  • The reusable harness deliverable — the audit-tag-to-HEAD commit manifest + Slither config + Aderyn invocation + reviewed-path manifest template — is a separate artifact from the report; its first-pass skeleton is captured in the commands block above and will be packaged as a standalone MIT-licensed repo at M2.

Reproducibility

All commands above are copy-pasteable. aderyn output at bold_aderyn.md is ~117 KB and can be regenerated deterministically from the same commit pin.

Tool versions:

  • aderyn 0.6.8
  • solc-select 0.8.28 (installed but not invoked on M1 — aderyn does not need solc; solc will be used for Slither in M2)
  • npm 10.x with --legacy-peer-deps
  • Node v22.x or compatible

Prior art cross-reference

A parallel 1-page Compound V3 audit-pipeline teaser produced 2026-04-24 on the same methodology, focused on contracts/marketupdates/ at Compound’s HEAD ed6ebcd. Content available via the same channel as this memo. Both memos share the same Aderyn-triage + manual-review skeleton; BoLD is substantially denser (10,883 vs 5,992 nSLOC) so the M2 pass will require proportional time.


This memo is unpaid M1 work posted publicly as proof-of-competence. If DDA 3.0 or a successor program funds the M2 full-report extension ($5,000 USDC, scoped in the parallel proposal), the full write-up ships at end of week 4. If not, the memo stands as a public methodology artifact.

Gm, Jojo here, current program manager of the D.A.O. Grant Program.

The D.A.O. Grant Program is neither suited nor in scope to evaluate what should be instead tunnelled into the bug bounty program of Arbitrum.

My suggestion for you is to read the about that program, and also focus on a responsible disclosure of any finding you might have at hand.

Thank you.