Updated after the second (April 2026) production-readiness sweep that closed every open P1 and every open P2. Every item flagged by the post-MVP review is now addressed; what remains is explicit P3 "v2.0-wants" work.
- P1 — Critical: should fix before public beta
- P2 — Important: should fix for v1.0 quality
- P3 — Enhancement: nice-to-have, required for v2.0
SolidityLinternow walks the raw@solidity-parser/parserAST for reentrancy, missing-event, storage-in-loop, unchecked-call, dangerous-delegatecall, and unprotected-selfdestruct detection. The regex versions fired on commented-out code and multi-line expressions; the AST versions don't.- Added 6 regression tests that specifically exercise the false-positive
cases the regex implementation would have hit (block-comment CEI,
delegatecall in a comment, emit-suppresses-missing-event, captured
tuple return on
.call, inlinemsg.senderaccess check for selfdestruct, loop-reads-parameter-shadow).
SolcBridge.findLocalReferences(filePath, offset)returns the declaration range + every reference range for a function-scoped variable.RenameProvider.provideLocalRenamerewrites precisely those byte ranges in a single file — no workspace-wide text rewrite needed.prepareRenamenow accepts locals when a SolcBridge is available (post-first-successful-build). Top-level symbols still go through the index-based path.- Updated the legacy rejection error to name the actual precondition (no symbol-index match AND no solc AST).
SolcBridgenow extractsevm.methodIdentifiersfrom the forge build output alongside the AST and exposes it viagetCachedMethodIdentifiers(contractName).CodeLensProviderconsults the cache first (Etherscan-accurate for structs / UDTs) and only falls back to local keccak256 when the cache is cold (pre-first-save or build failure).- Handles overloads by matching parameter count.
deploy.ts::pickContractnow enumeratesout/**/*.jsonForge artifacts for the authoritative deployable-contract list. Skips interfaces (empty bytecode), build-info files, and Test/Mock names automatically. Falls back to the legacy regex-over-src path when no artifacts exist (fresh clone, no build yet).- When the artifact has an ABI, the constructor-args prompt becomes
per-parameter with declared Solidity type in the prompt label.
String values are auto-quoted for
forge create.
@vscode/test-electronis wired up:packages/extension/src/test/runTest.tsboots a real VSCode binary (cached in.vscode-test/) with the extension loaded and thetest/fixtures/sample-project/as the workspace.packages/extension/src/test/suite/contains the Mocha suite.pnpm --filter solidity-workbench test:e2eis now a first-class test command, and a newe2eCI job runs it underxvfb-runon GitHub Linux runners.
- The initial smoke suite has 6 tests (all green) covering: extension
presence, activation, 13 key commands registered, Solidity language
registered,
.solfiles open with the rightlanguageId, and the LSP returns document symbols for the sampleCounter.solcontract.
- LCOV parser extracted from
extension/src/views/coverage.tsinto@solidity-workbench/common/lcov.tsso the server'snode --testrunner can exercise it. Added 14 tests covering every LCOV record type (DA/BRDA/LF/LH/FN/FNDA/ ...), CRLF tolerance, branch summarization, and derivedLF/LHtotals. - Added provider-level tests for:
CompletionProvider— keywords, types, user-defined symbols, NatSpec tags, import paths,msg. / abi., staticContract.member lookup with visibility filtering (7 tests)AutoImportProvider— remapped-vs-relative path selection, undeclared-identifier quick fixes, irrelevant-diagnostic suppression (4 tests)CodeActionsProvider— add-SPDX, replace-tx.origin, add-NatSpec idempotence, implement-interface stubbing with override keyword placement (5 tests)DiagnosticsProvider.extractSyntaxDiagnostics— SPDX, floating pragma,tx.origin, deprecatedselfdestruct, comment suppression (9 tests)
- Server test count: 135 → 181.
See git history for full detail. Highlights retained here for cross-reference:
- SolcBridge rich AST consumed by hover / definition / completion providers for overload disambiguation and member resolution.
- Test Explorer backed by a custom
solidity-workbench/listTestsLSP request sourced from the parsed AST. - Line-level coverage via
forge coverage --report lcov. - Gas profiler regression deltas persisted to
context.globalState. - Multi-root workspace support with per-root
foundry.toml/ remappings / source trees. - Cancellation tokens across every heavy LSP request.
- Full dynamic config reload for every
solidity-workbench.*setting. - Status bar wired to a
solidity-workbench/serverStatenotification. foundry.tomlIntelliSense expanded torpc_endpoints,etherscan.*,fuzz,invariantplus every[profile.*]key.- Inlay-hint paren-aware argument walker and declaration-line guard.
- LICENSE / CHANGELOG / icon / telemetry disclaimer / tag-gated publish workflow in place.
None.
None.
- New
TrigramIndexunderpackages/server/src/analyzer/maintains a map from 3-grams to symbol names.SymbolIndex.findWorkspaceSymbolsnow prunes candidates via posting-list intersection for queries of 3+ chars, ranks matches viascoreName(exact > prefix > substringordered-subsequence fuzzy), and caps at 100 results. Includes full add / remove lifecycle so symbols removed from the workspace no longer leak into search. 15 new unit tests across
trigram-index.test.ts+symbol-index.test.ts.
- Pure JSON-report parser added to
@solidity-workbench/common/aderyn-reportwith 11 unit tests covering malformed input, the three severity buckets, tuple params, and schema drift tolerance. AderynIntegrationVSCode wrapper mirrors the Slither shape — newsolidity-workbench.aderyncommand,aderyn.enabled/aderyn.pathsettings, and opt-in on-save hook. Writes the report to a tempdir, parses it, maps tovscode.Diagnosticwith related-information links between instances.
generateSubgraphScaffoldin@solidity-workbench/commonemitssubgraph.yaml,schema.graphql, andsrc/<contract>.tsfor a contract ABI. Events-only scaffold with correct indexed-param canonical signatures, scalar / array type mapping, and explicit// TODOmarkers for tuple params whose encoding is domain-specific. 16 unit tests cover the ABI → files transformation.solidity-workbench.subgraph.scaffoldcommand picks a compiled contract fromout/*.sol/*.json, prompts for network / address / start block, writes the scaffold files plus a copy of the ABI intosubgraph/<ContractName>/, and opens the manifest.
- Pure JSON-report parser added to
@solidity-workbench/common/wake-reportwith 12 unit tests covering the canonical and legacy top-level shapes, field-name fallbacks across Wake versions (detector_name/detector/name,impact/severity,source_unit_name/file/path,line_from/line/start_line),location.start: [line, col]tuples, dedup of subdetections, and informational-impact aliases. WakeIntegrationVSCode wrapper mirrors the Aderyn shape — newsolidity-workbench.wakecommand,wake.enabled/wake.pathsettings, and an opt-in on-save hook. Captures stdout (Wake has no--outputflag), parses, and surfaces each finding with column-precise ranges where Wake provides them and the confidence rating in the diagnostic message.
- Pure JSON-report parser added to
@solidity-workbench/common/mythril-reportwith 11 unit tests covering all three top-level shapes Mythril emits (single-target{ issues: [...] }, multi-target keyed-by- filename, bare-array form), severity normalisation includingInformational/Info/Informationaliases, SWC field aliases (swc-id/swcID/swc_id), and dropping of malformed entries. MythrilIntegrationVSCode wrapper differs from the others because Mythril's symbolic-execution runtime is too slow for whole-workspace scans:- Per-file: command + on-save hook target a single Solidity file (the active editor's file by default).
- Long-running progress:
withProgressshows a status-bar spinner while the analysis runs (10-minute timeout cap). - In-flight guard: a save burst won't stack analyses.
- SWC tagging: each diagnostic's
codeis the SWC registry id (SWC-107,SWC-101, ...) when present. solidity-workbench.mythril.enableddefaults tofalse— opt-in to avoid a save-time stall.
- Corrected the stale
uniswap.solidity-workbenchextension ID in the activation smoke tests (publisher isccashwell). - Extended command-registration assertions to cover the three new
commands (
aderyn,subgraph.scaffold,findReferencesAt). - Added
lsp-round-trip.test.tswith tests for hover, workspace symbols (exact + fuzzy subsequence), references, rename response, code actions response, and formatting response. Retry loop tolerates the asynchronous initial indexing pass.
- New
solidity-workbench.remoteChain.opencommand opens a webview that wrapscast callagainst a chain picker, with ABI awareness so args are typed. Seven seeded public RPCs (Mainnet, Sepolia, Base, Base Sepolia, Optimism, Arbitrum One, Polygon PoS) plus a "Custom RPC URL…" escape hatch. ABI loaded by pasting JSON or picking a forge artifact underout/**/*.json. Function picker groups read-only and write methods; writes are rendered disabled with a deferral tooltip. Result cards show raw hex AND decoded text with copy buttons. Pure helpersformatFunctionSignature,formatFunctionDisplaySignature,formatFunctionSignatureWithReturns, andisReadOnlyship in@solidity-workbench/common/abi-signaturewith 27 unit tests.cast decode-outputdoes not exist on Foundry 1.5; the panel uses cast's built-in inline decoding vianame(in)(out)signatures instead.
- The legacy
ChiselIntegrationshelled chisel into avscode.Terminal. Replaced withChiselPanel— a webview that owns a long-livedchiselsubprocess spawned viachild_process.spawn, renders each evaluation as a card, and persists history (capped at 200 entries) incontext.globalState. The three command IDs (solidity-workbench.chisel.start,.startFork,.sendSelection) keep working unchanged. Subprocess teardown fires on both panel disposal and extension deactivate (SIGTERM with a 1 s SIGKILL fallback). Pure helpers in@solidity-workbench/common/chisel-outputwith 28 new unit tests cover ANSI stripping, banner consumption, multi-chunk buffering, error classification, and exit-time drain. Pairing strategy is a quiet-window heuristic, not a prompt sentinel — chisel's reedline frontend disables its➜prompt under non-TTY stdio, so prompt-based parsing was infeasible.
A real DAP adapter that launches forge / cast with trace output, parses solc source maps, walks opcodes, and implements the DAP request set. All five originally-scoped stages landed in the May 2026 sweep.
Stage 1 — scaffold (DONE). May 2026 sweep:
- Pure
parseSourceMap/buildPcToInstructionIndex/resolveSourcePositionhelpers in@solidity-workbench/common/source-mapwith 17 unit tests covering compression rules, thefileIndex = -1sentinel, PUSH1– PUSH32 + PUSH0 operand walks, hex-prefix tolerance, and recoverable map-shorter-than-bytecode mismatches. SolidityDapAdapter(inlineDebugAdapterInlineImplementation) speaks the DAP wire format directly. Stubs initialize / launch / threads / stackTrace / scopes / variables / step* / terminate. Unimplemented requests returnsuccess: falsewith a "Not yet implemented" message rather than blocking the host.package.jsondeclaresbreakpoints: [{ language: "solidity" }], thesolidity-workbenchdebug type with a launch.json schema (program,test,stopOnEntry), an initial config, and an auto-completer snippet.SolidityDapConfigurationProviderfills in defaults for F5-without-launch.json.
Stage 2 — trace ingestion (DONE). May 2026 sweep:
parseTraceJsonaccepts the de-factodebug_traceTransactionJSON shape (geth, anvil,cast run --json) plus two defensive variants ({ steps: [...] }and a bare array). Tolerant of the field-name drift Foundry emitters exhibit (pc/programCounter,op/opName/opcode,gas/gasLeft,gasCost/cost) and gas values serialised as either decimal numbers or0xhex.TraceCursoris the navigator the DAP adapter holds for the session:current/index/length/next/previous/seek/findNext/findPrevious. Cheap index moves; source-position-aware semantics composefindNextwith a predicate built from the source-map module so the cursor itself stays source-map-agnostic.- 16 unit tests cover the three top-level shapes, field aliases, gas-as-hex-or-decimal, optional-field defaults, error capture, and every cursor method's edge cases.
- The DAP adapter's launch config gained a
traceFileescape hatch. When set, the adapter parses the JSON, builds aTraceCursor, andstackTrace/next/stepIn/continue/terminatedall flow through real cursor state. Until the live execution path lands in stage 3, users can hand-feedcast run --jsonoutput and step opcode-by-opcode.
Stage 3 — source-position resolution + step semantics + setBreakpoints (DONE). May 2026 sweep:
- New
parseForgeArtifactin@solidity-workbench/commondecodes forge artifacts (out/<File>.sol/<Contract>.json) tolerating the canonical / flat-string /evm.<key>shapes that Foundry has emitted across versions. Source list extracted frommetadata.sources(canonical solc metadata key order = fileIndex), with fallbacks to top-levelsources/sourceList. 11 unit tests. LineIndexmoved into common so the adapter shares one canonical UTF-8-byte ↔ LSP-position implementation with the LSP server.- The adapter loads the artifact during
launch, builds aContractContext(parsed sourceMap, pre-computed PC → instruction-index table, absolute source paths each indexed for byte-offset → line conversion), and:stackTracereports actual file + line + column.next/stepInadvance until the source line changes.stepOutruns until call depth drops below the current frame.continueadvances to the next breakpoint or end.setBreakpointsrecords source-line breakpoints keyed on normalised absolute path.loadedSourcesenumerates the artifact's source list.
- Single-contract caveat: when a trace enters an external CALL / CREATE the inner contract's bytecode + sourceMap aren't ours, so stepping shows label-only frames at depth > 1 until the call returns.
Stage 4 — internal call stack + Stack / Memory / Storage scopes (DONE). May 2026 sweep:
stackTracewalksjump: "i"/jump: "o"markers from index 0 through the cursor's current step to construct the Solidity internal call stack. Each internal function call is its own DAP frame with its own source position. The DAP convention is topmost-first; the topmost frame's name carries the PC/opcode/depth context. Defensive against unbalanced jumps from exception unwinds.scopesexposes Stack (uint256 entries, top-of-stack first), Memory (32-byte words by start offset), and Storage (slot → value entries from structLogs) at the current step. Each scope name carries a count badge.variablesresolves the references through a per-step allocation table cleared at every freshscopesrequest, so stale references can't survive a step transition.
Stage 5 — disassembly + storage pretty-print + evaluate (DONE). May 2026 sweep:
parseStorageLayoutin common reads the artifact'sstorageLayoutblock and groups packed entries by slot. Storage scope entries surface as<label> (slot 0xN [+offset]) = <value>with the Solidity type attached. 8 unit tests.disassemblehelper in common decodes EVM bytecode through Cancun / post-Cancun (BLOBHASH, BLOBBASEFEE, MCOPY, TLOAD, TSTORE, PUSH0). Unknown opcodes render asINVALID(0xNN)rather than throwing. The deployed bytecode is disassembled once at load anddisassemblerequests slice instruction windows out of the cache. 7 unit tests.evaluaterequest supports a small expression DSL:stack[N],memory[0xN],storage[<slot>], and bare state-variable identifiers resolved through the storage layout.supportsEvaluateForHoversflipped on so VSCode's hover surfaces values inline.
Stretch goals (DONE). May 2026 sweep:
- Live
cast run --jsonlaunch path. SettingtxHash(and optionallyrpcUrl/castPath) in launch.json makes the adapter spawncast run --json <txhash>itself instead of requiring a hand-saved trace file. 10-min timeout, 256 MB stdout buffer, ingests on cast non-zero exit (revert) too. - AST-driven Locals scope + named call frames. New
extractFunctions/findEnclosingFunctionhelpers in@solidity-workbench/commonwalk the artifact's compactAST (and legacyAST) for FunctionDefinition nodes with their parameters and locally-declaredVariableDeclarations. Internal call-stack frames use the actual Solidity function name; the "Source-level locals" scope lists the enclosing function's parameters and in-scope locals (out-of-scope ones filtered via the AST node'ssrcbyte range). 8 unit tests on the AST walker. - Multi-contract source maps. Launch config gains a
contracts: [{ address, artifact, projectRoot? }]array. The adapter loads each into anauxContextsmap keyed by address, walks the trace once at launch to build a per-step(ContractContext | null)[]stream (CALL / STATICCALL / DELEGATECALL targets read from the stack), and routesresolveStepSource/ storage pretty-print / disassembly / identifier-evaluate throughactiveContext()instead of the fixed entry contract.loadedSourcesunions every loaded contract's source list so VSCode's panel shows them all.
Follow-on items shipped (May 2026 sweep continued).
- Per-depth internal call stacks. The call-stack walker
(
buildCallStackin the adapter) maintains an independent internal-frame stack per EVM call depth. Eachjump: "i"pushes within the active depth; eachjump: "o"pops. EVM CALL / STATICCALL / DELEGATECALL / CREATE boundaries pause the outer depth's stack and start a fresh one at the inner depth, seeded with a frame anchored to the inner contract's first source-resolvable step (named after the enclosing function via the AST when resolvable). The flattened result is topmost-first per the DAP convention. The walker also computes per-frameentryStepIdx,entryStackLen, the resolvedAstFunction, the activeContractContext, and alocalStackPositions: Map<string, number>— foundation for live local resolution. - Live parameter and local values. The Source-level
locals scope reads live values from the trace's EVM stack:
- Parameters at
[entryStackLen - paramCount, entryStackLen)per Solidity's standard calling convention. Stack-shrunk-below-slot renders as(consumed by callee). - Locals tracked incrementally by the walker — when the
trace's source position passes a
VariableDeclarationStatement's end byte and the EVM stack has grown beyondentryStackLen, the slot at the top of the stack is recorded into the frame'slocalStackPositionsmap. Subsequent reads pull fromstep.stack[recordedSlot]. Edge cases surface as informative placeholders rather than wrong values:(initializer running),(unsupported declaration form),(consumed). Theevaluaterequest gains the same lookup so hovering over an in-scope identifier resolves live values, matching Solidity's lexical resolution order (local/param shadows state).
- Parameters at
Caveats remaining: tuple destructuring ((a, b) = foo())
locals fall through to the (unsupported declaration form)
placeholder; legacy-codegen mode (no via-IR) can consume
parameters early so values display as (consumed) faster than
expected. Both are surfaced as informative messages rather
than wrong values.
paradigmxyz/solar PR #401 is merged but not yet in a released Solar
crate. When Solar ships a stable LSP, evaluate swapping the parser +
resolver hot path via WASM for ~40× speed and true type resolution.
Effort: 2–3 weeks once Solar is ready.
Third-sweep work added LSP round-trip tests (hover, workspace
symbols + fuzzy, references, rename, code actions, formatting).
The May 2026 sweep added a feature-coverage.test.ts suite — 13
tests covering more LSP providers (diagnostics, code lens, inlay
hints, document highlights, type definition), webview / static-
analysis command registration, Test Explorer controller wiring,
and a synthetic-trace DAP launch round-trip that exercises the
adapter end-to-end via VSCode's debug API.
Natural next additions: coverage decoration rendering, full-trace
DAP source resolution against a real forge build (rather than
the synthetic minimal artifact), Slither / Aderyn diagnostic
round-trip with a fixture report.
Effort: 1–2 days ongoing.
| Priority | Count | Cumulative effort |
|---|---|---|
| P1 | 0 | — |
| P2 | 0 | — |
| P3 | 2 | ~2–3 weeks |
| Total to public beta | 0 | ship the VSIX | | Total to v1.0 | 0 | ship the VSIX |
As of this sweep there are no open P1 or P2 items. Every concern the
post-MVP review raised has landed: AST-based linting eliminates the
comment / multiline false positives; locals / parameters rename via
SolcBridge; selectors come from forge build output; the deploy
picker offers type-aware constructor prompts; and there's a real
@vscode/test-electron suite running in CI. The remaining work is
strictly P3 — nice-to-haves and v2.0 stretch items.