You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
paramType is string | undefined due to optional chaining calledFunc.parameters[i]?.type. The guard if (!substitutions.has(paramType)) does not exclude undefined, so when a parameter has no type the code executes substitutions.set(undefined, argValue). JavaScript Map silently accepts undefined as a valid key. The resulting entry can never be matched by a real type string lookup, and on a second iteration the first-wins guard silently drops a legitimate substitution.
if (paramType !== undefined && !substitutions.has(paramType)) {
substitutions.set(paramType, argValue)
}
Bug 2: REF_/TMP_ fallback picks an arbitrary map entry when multiple substitutions exist
parentSubstitutions.values().next().value// line 938typeSubstitutions.values().next().value// line 1022
This picks the first inserted entry by Map insertion order. When the map has exactly one entry (the single-parameter case this PR was designed for) it is correct. But buildTypeSubstitutionMap creates one entry per distinct-typed parameter, so a function with two typed parameters — e.g., _compute(OracleA a, OracleB b) — produces {OracleA → ethUsdOracle, OracleB → btcUsdOracle}. If the REF_ was derived from b.aggregator, the fallback silently resolves to ethUsdOracle (wrong) instead of btcUsdOracle.
The comment at line 1020 acknowledges this with "internal functions typically have one relevant parameter" — this is a heuristic assumption, not a guarantee, and produces a wrong call graph edge with no warning when it doesn't hold.
Bug 3: VariableChainHeuristic nested-object branch lacks ABI validation
The new nested-object branch returns all eth: addresses found in the struct with confidence 100 (single address) or 70 (multiple), without checking whether those addresses implement the called function. The DiscoveredValuesScanHeuristic added in the same PR correctly calls contractHasFunction() before returning any candidate — but VariableChainHeuristic always wins on confidence (100 vs 95), so the less-validated path overrides the more careful one.
Concrete failure case: a struct { fallbackFeed: "eth:0xWrong", aggregator: "eth:0xChainlink" } where only 0xChainlink has latestRoundData() would resolve to 0xWrong if it appears first in JSON order, with confidence 100 and no error.
Suggested fix: add the same contractHasFunction filter used by DiscoveredValuesScanHeuristic inside this branch, mirroring lines 364–374.
Issue 4: contractHasFunction is undocumented as unexported but CLAUDE.md describes it as a shared helper
contractHasFunction is defined without export, making it a private module-level function. However, CLAUDE.md — updated in this same PR — lists it under "Shared Traversal Helpers" alongside genuinely exported functions from callGraph.ts (traverseWithPaths, extractEthAddresses, etc.), implying it is importable by other modules. Any developer following the docs and trying to import contractHasFunction in e.g. functionAnalysis.ts would get a compile error.
Either add export to the function definition (if cross-module use is intended) or update CLAUDE.md to clarify it is internal to callGraphHeuristics.ts.
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
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.
Improving the callgraph for a special case in liquity where the contract calls 2 different oracles,
we now differentiate the calls and register the two dependencies.
Some small fixes in the liquity-v2 config as well.