Skip to content

chore: bump biome to 2.4.14 and enforce stricter lint rules#583

Merged
0xbulma merged 3 commits into
mainfrom
0xbulma/biome-max-params
May 4, 2026
Merged

chore: bump biome to 2.4.14 and enforce stricter lint rules#583
0xbulma merged 3 commits into
mainfrom
0xbulma/biome-max-params

Conversation

@0xbulma
Copy link
Copy Markdown
Collaborator

@0xbulma 0xbulma commented May 4, 2026

Summary

  • Bump @biomejs/biome 1.9.4 → 2.4.14, migrate biome.json to v2 schema (files.includes, assist.actions).
  • Enable complexity/useMaxParams (max=2), style/noParameterAssign, style/noUselessElse, and nursery rules noFloatingPromises, noMisusedPromises, noShadow, useExhaustiveSwitchCases. All 366 existing violations are suppressed with rule-specific // biome-ignore … TODO … comments so the lint pass stays green while leaving a clean refactor backlog.
  • Disable suspicious/noNonNullAssertedOptionalChain and suspicious/useIterableCallbackReturn (newly recommended in 2.x; out of scope for this change).
  • Update scripts/lint/checksum-address.js to read the new files.includes shape and absorb v2's JSON formatter / organizeImports output across the monorepo.

Test plan

  • pnpm install succeeds; pnpm biome --version reports 2.4.14
  • pnpm lint exits 0
  • pnpm test for morpho-ts and simulation-sdk (non-RPC) passes locally
  • CI green on the PR

🤖 Generated with Claude Code


Open in Devin Review

- Migrate biome.json to v2 schema (files.includes, assist.actions)
- Enable complexity/useMaxParams (max=2) — 244 violations annotated with
  // biome-ignore + TODO refactor to ≤2 params
- Enable nursery/noFloatingPromises, noMisusedPromises, noShadow,
  useExhaustiveSwitchCases; style/noUselessElse, noParameterAssign —
  122 violations annotated with rule-specific TODO ignores
- Disable suspicious/noNonNullAssertedOptionalChain and
  useIterableCallbackReturn (new in 2.x recommended set; out of scope)
- Update scripts/lint/checksum-address.js to read v2 files.includes
- Absorb v2 formatter changes (JSON, organizeImports)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@0xbulma 0xbulma requested a review from Rubilmax May 4, 2026 08:56
@0xbulma 0xbulma self-assigned this May 4, 2026
@0xbulma 0xbulma requested a review from Foulks-Plb May 4, 2026 08:57
@Foulks-Plb
Copy link
Copy Markdown
Collaborator

@codex reivew

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Foulks-Plb
Foulks-Plb previously approved these changes May 4, 2026
@0xbulma 0xbulma enabled auto-merge (squash) May 4, 2026 09:08
… barrel cycle

aaveV2/aaveV3/compoundV3 (borrow) and aaveV2/aaveV3/aaveV3Optimizer/
compoundV2/compoundV3 (supply) imported their base class through the
folder's ./index.js barrel. The cycle only loaded successfully when the
base class re-export came first; Biome v2's organizeImports sorts
PascalCase after lowercase, putting MigratableBorrowPosition.js last and
causing "Class extends value undefined" at module evaluation.

Import the base class directly from its source file to break the cycle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@0xbulma 0xbulma merged commit 637d5fb into main May 4, 2026
7 checks passed
@0xbulma 0xbulma deleted the 0xbulma/biome-max-params branch May 4, 2026 09:22
0xbulma added a commit that referenced this pull request May 4, 2026
Biome 2.4.14 (bumped on main in #583) enforces stricter import sorting.
The CI lint job failed with `assist/source/organizeImports` on
packages/morpho-test/src/fixtures/tokens.test.ts.

Auto-fixed via `biome check --write` — single-character reorder of
the named imports from "@morpho-org/blue-sdk" so that addressesRegistry
precedes ChainId alphabetically.

Verification:
- pnpm lint -> no errors (2 unrelated warnings on codegen.ts and
  1 info on anvil.ts pre-date this branch).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0xbulma added a commit that referenced this pull request May 19, 2026
* docs(tibs): propose colocated vitest coverage migration

Adds TIB-2026-04-27 describing the convention switch to colocated
*.test.ts files across the eight in-scope SDK packages, the canonical
viem transport-level mock and nock-based HTTP/GraphQL patterns, and
an eight-phase rollout sequenced easiest-first.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(tibs): refocus TIB on maximizing unit-test coverage

Renames TIB-2026-04-27 from "colocated vitest coverage" to
"maximize unit-test coverage of SDK packages" — colocation is
demoted to one of four implementation conventions, alongside
viem transport-level mocking, nock for HTTP/GraphQL, and the
*.integration.test.ts naming for fork-bound tests.

Adds a coverage baseline section captured locally with
`pnpm test:coverage --project <name> --coverage.reportOnFailure=true`
across all in-scope projects, including:
- per-project pass/fail and coverage breakdown
- per-package lcov-merged line coverage table
- list of zero-coverage files of note (e.g. LiquidationEncoder.ts at
  0% / 1,001 LOC, MetaMorphoAction.ts at 0% / 332 LOC,
  liquidity-sdk-viem/loader.ts at 0%)
- list of <30% files (BundlerAction at 16.52%, midas tokens at 2.70%)

Each phase now has a concrete coverage target (≥ 80–95% line) and
explicitly names the zero-coverage files it must address.

Adds barrel `index.ts` to coverage exclusion (the long zero-coverage
tail in the report has no real code).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(tibs): scope TIB to adding unit tests, not migrating fork tests

Tightens the TIB so the only change to existing tests is "none."
Existing files under packages/X/test/ — fork-based, e2e, or
otherwise — keep their paths, names, imports, and contents. The
TIB now strictly adds new colocated unit tests in src/ alongside
them. Both layouts coexist for the lifetime of the TIB.

- Goals/Non-Goals: explicit non-goal that no existing test is
  moved or refactored.
- Convention 1 (Colocation): scoped to NEW unit tests; layout
  diagram shows the existing test/ directory marked UNTOUCHED.
- Convention 4: replaced "rename fork tests to *.integration.test.ts
  and relocate" with "existing tests are not touched."
- vitest.config.ts: include is now a UNION of test/**/*.test.ts and
  src/**/*.test.ts, so both layouts run side by side.
- Implementation Phases: each phase only ADDS files in src/; no
  git mv, no path rewrites in existing tests.
- Considered Alternatives: adds rejection for "migrate existing
  fork tests too" (unnecessary churn for no coverage gain).
- Open Questions: drops the *.integration.test.ts naming question
  (now moot); keeps the "are there fork-only files" question.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(morpho-ts): phase 1 — colocated unit tests, raise coverage to 96%

Implements TIB-2026-04-27 phase 1.

Config:
- vitest.config.ts: union the morpho-ts project include to match both
  the existing test/ files (untouched) and new src/**/*.test.ts.
- vitest.config.ts: tighten coverage.exclude to drop *.test.ts,
  __test-utils__/, barrel index.ts, abis.ts, and api codegen.
- packages/morpho-ts/tsconfig.build.{cjs,esm}.json: exclude src/**/*.test.ts
  and __test-utils__/ from emitted lib/.

New colocated unit tests (no existing test in test/ moved or modified):
- src/urls.test.ts: ZERO_ADDRESS, getSubdomainBaseUrl, all subdomain consts.
- src/utils.test.ts: every public utility (predicates, comparator, dotted
  path access, keys/values/entries/fromEntries/mergeEntries,
  retryPromiseLinearBackoff, deepFreeze, getLast/filterDefined).
- src/time/time.test.ts: full unit-conversion matrix and fromPeriod/toPeriod,
  plus Time.wait and Time.timestamp.
- src/format/array.test.ts: formatUnion, formatEnumeration.
- src/format/string.test.ts: formatLongString edge cases.
- src/format/locale.test.ts: getLocaleSymbols, getEffectiveLocale,
  convertNumStrToLocal, convertNumStrFromEffectiveTo,
  getEnUSNumberToLocalParts. Browser globals stubbed via vi.stubGlobal.

Verification:
- 9 test files / 265 tests pass (project: morpho-ts).
- Coverage: morpho-ts line coverage 78.60% -> 96.32% (288/299).
  utils.ts, urls.ts, format/array.ts, format/string.ts now at 100%.
- pnpm --filter @morpho-org/morpho-ts build succeeds.
- find packages/morpho-ts/lib -name "*.test.*" returns empty.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

# Conflicts:
#	vitest.config.ts

* test(test): phase 2 — shared createMockClient/mockRead helpers + tests

Implements TIB-2026-04-27 phase 2.

New module @morpho-org/test/mock:
- createMockClient(chain): viem Client backed by a vi.fn() that intercepts
  JSON-RPC at the transport level. Required for SDK code using viem/actions
  named imports (readContract(client, ...)) — those resolve through
  client.transport, not via methods on the client object.
- mockRead({ address, abi, functionName, result }): pre-program eth_call
  responses by selector; multiple stack with last-write-wins semantics.
- expectReadCall(...): inspect mock call history and decode args.

Config:
- packages/test/package.json: ./mock sub-export wired into exports,
  typesVersions, and publishConfig.exports.
- packages/test/tsconfig.build.{cjs,esm}.json: exclude src/**/*.test.ts
  and __test-utils__/ from emitted lib/.
- vitest.config.ts: union test project include with src/**/*.test.ts.

Tests (24 pass):
- src/mock.test.ts: chain id default & override, unhandled-method throws,
  mockRead by selector + address case-insensitive, distinct functions,
  last-write-wins, abi validation, expectReadCall filtering.
- src/fixtures.test.ts: randomAddress structural shape, testAccount
  derives canonical Anvil accounts deterministically.

Existing test/utils.test.ts is unchanged (still requires fork RPC).

Verification:
- pnpm test --project test --run packages/test/src -> 24/24 pass.
- pnpm --filter @morpho-org/test build succeeds with mock.js + mock.d.ts.
- find packages/test/lib -name "*.test.*" -> empty.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(blue-sdk): phase 3 — colocated unit tests for math, errors, tokens, vaults

Implements TIB-2026-04-27 phase 3 — focused on the zero-coverage files
the TIB baseline called out, plus the foundational math libraries.

Config:
- vitest.config.ts: union the blue-sdk project include with src/**/*.test.ts.
- packages/blue-sdk/tsconfig.build.{cjs,esm}.json: exclude src/**/*.test.ts
  and __test-utils__/ from emitted lib/.

New colocated unit tests (existing test/unit/* and test/e2e/* untouched):
- src/math/MathLib.test.ts: WAD/RAY/MAX_UINT_*, maxUint, abs/min/max,
  zeroFloorSub, mulDiv (Down/Up, divide-by-zero), wMul, wDiv, wTaylor-
  Compounded, wToRay. → 100% coverage.
- src/math/SharesMath.test.ts: VIRTUAL_SHARES/ASSETS, toAssets/toShares
  with empty pool & non-empty pool, rounding direction, monotonicity,
  round-trip bias. → 100% coverage.
- src/math/AdaptiveCurveIrmLib.test.ts: wExp clipping (LN_WEI_INT,
  WEXP_UPPER_BOUND), monotonicity, getBorrowRate first-interaction and
  subsequent paths, getUtilizationAtBorrowRate full curve sweep,
  clamping. → 100% coverage.
- src/errors.test.ts: every error class incl. BlueErrors and VaultV2Errors
  namespaces, _try sync/async with matching/non-matching error classes
  and subclasses. → 100% coverage.
- src/preLiquidation.test.ts: registry shape (8 LLTV tiers, 5 fields each),
  invariants (preLCF2 > preLCF1, preLIF >= 1 WAD, preLltv < lltv),
  getDefaultPreLiquidationParams success and unsupported throw.
  → 100% coverage.
- src/token/Token.test.ts: constructor field storage and BigIntish coercion,
  Token.native, fromUsd/toUsd round-trip, rounding direction. → 100%.
- src/token/ConstantWrappedToken.test.ts: decimal scaling, slippage ignored,
  exact-in/exact-out helpers. → 100%.
- src/token/ExchangeRateWrappedToken.test.ts: rate storage, wrap/unwrap
  with various rates, slippage propagation. → 100%.
- src/holding/AssetBalances.test.ts: constructor seed, add accumulation,
  sub decrement, chainability, all peripheral balance types. → 100%.
- src/user/User.test.ts: field storage and mutability. → 100%.
- src/vault/VaultUser.test.ts: field storage. → 100%.
- src/vault/VaultConfig.test.ts: decimals=18 forced, asset+decimalsOffset
  preserved. → 100%.
- src/vault/VaultMarketPublicAllocatorConfig.test.ts: field storage. → 100%.

Verification:
- pnpm test --project blue-sdk --run packages/blue-sdk/src
  -> 13 files, 148 tests pass.
- pnpm --filter @morpho-org/blue-sdk build succeeds.
- find packages/blue-sdk/lib -name "*.test.*" -> empty.
- Files moved from 0% baseline to 100%: AssetBalances, ExchangeRate-
  WrappedToken, VaultUser. Math libraries also at 100%.

Out of scope for this phase: the large classes (Market 812 LOC,
MarketUtils 630, Vault 459, Position 342, VaultV2 288) which remain
covered by existing test/ files; their colocated unit tests can be
extended in a follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(morpho-test): phase 4 — colocated fixture validation tests

Implements TIB-2026-04-27 phase 4. Adds morpho-test as a new vitest
project (previously unrun) and 3 colocated test files validating the
canonical fixtures.

- vitest.config.ts: new "morpho-test" project, include src/**/*.test.ts.
- packages/morpho-test/tsconfig.build.{cjs,esm}.json: exclude tests +
  helpers from emitted lib/.
- src/fixtures/markets.test.ts: 4-chain registry shape, MarketParams
  invariants, idle market check, market id determinism, randomMarket.
- src/fixtures/vaults.test.ts: VaultConfig invariants, decimalsOffset,
  randomVault defaults.
- src/fixtures/tokens.test.ts: withSimplePermit registry shape and
  canonical addresses.

24 tests pass; build succeeds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(liquidity-sdk-viem): phase 5 — colocated unit tests + nock GraphQL pattern

Implements TIB-2026-04-27 phase 5.

Config:
- vitest.config.ts: union liquidity-sdk-viem project include with
  src/**/*.test.ts.
- packages/liquidity-sdk-viem/tsconfig.build.{cjs,esm}.json: exclude
  src/**/*.test.ts and __test-utils__/ from emitted lib/.

Tests (12 pass):
- src/api/index.test.ts: apiSdk shape, getMarkets via nock against
  BLUE_API_GRAPHQL_URL (success, empty items, GraphQL error path),
  getSdk + custom endpoint round-trip. Establishes the canonical
  nock pattern for GraphQL mocking.
- src/loader.test.ts: LiquidityLoader constructor stores client and
  parameters, default empty params, fetch method exposed and returns
  a Promise, maxWithdrawalUtilization override.

The existing test/loader.test.ts (fork-based, exercises the full
SimulationState path) is left untouched.

Verification:
- pnpm test --project liquidity-sdk-viem --run packages/liquidity-sdk-viem/src
  -> 2 files / 12 tests pass.
- pnpm --filter @morpho-org/liquidity-sdk-viem build succeeds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(test): tighten createMockClient client type to Client<CustomTransport, chain>

Followup to Phase 2: the previously over-erased Client type prevented
mock clients from satisfying SDK signatures expecting Client<Transport, Chain>
(observed in Phase 5's loader.test.ts). Tighten MockClientHandle.client to
Client<CustomTransport, chain> so it slots in everywhere a typed client
is required.

Also fixes Phase 5 loader.test.ts to cast string literal to MarketId
brand and import MarketId type.

Verification:
- pnpm --filter @morpho-org/test build succeeds.
- pnpm --filter @morpho-org/liquidity-sdk-viem build succeeds.
- All previous tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(bundler-sdk-viem): phase 6 — colocated tests for errors + ActionBundle

Implements TIB-2026-04-27 phase 6.

Config:
- vitest.config.ts: union bundler-sdk-viem project include with
  src/**/*.test.ts.
- packages/bundler-sdk-viem/tsconfig.build.{cjs,esm}.json: exclude
  src/**/*.test.ts and __test-utils__/ from emitted lib/.

Tests (15 pass):
- src/errors.test.ts: every BundlerErrors class — Bundle (wraps inner
  error, preserves index/op/steps/stack), MissingSignature, MissingSwapData,
  UnexpectedAction (chainId in message), UnexpectedSignature, MissingSkim-
  Handler, UnskimedToken.
- src/ActionBundle.test.ts: ActionBundleRequirements (defaults, sign
  aggregation), ActionBundle (chainId branch, SimulationResult branch,
  tx()/txs() shape).

Existing fork-based tests in test/ untouched.

Verification:
- pnpm test --project bundler-sdk-viem --run packages/bundler-sdk-viem/src
  -> 2 files, 15 tests pass.
- pnpm --filter @morpho-org/bundler-sdk-viem build succeeds.
- find packages/bundler-sdk-viem/lib -name "*.test.*" -> empty.

Out of scope for this PR: BundlerAction.ts (2,346 LOC, dozens of
encoders) and operations.ts/actions.ts which need extensive ABI
round-trip suites; can land in follow-ups.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(blue-sdk-viem): phase 7 — colocated unit tests for utils, error, augment, fetchMarketParams

Implements TIB-2026-04-27 phase 7.

Config:
- vitest.config.ts: union blue-sdk-viem project include with
  src/**/*.test.ts.
- packages/blue-sdk-viem/tsconfig.build.{cjs,esm}.json: exclude
  src/**/*.test.ts and __test-utils__/ from emitted lib/.

Tests (38 pass):
- src/error.test.ts: isUnknownOfFactoryError predicate (plain Error,
  non-Error, BaseError without revert, ContractFunctionRevertedError
  with/without matching errorName, nested cause walking).
- src/utils.test.ts: safeParseNumber (integer/decimal/scientific/zero/
  negative), safeParseUnits (truncation, leading dot, invalid input,
  negative), safeGetAddress (EIP-55 normalization + invalid throws),
  restructure (named ABI -> object, unnamed throws, missing function
  throws).
- src/augment/augment.test.ts: every augmented blue-sdk class has a
  static fetch wired (Market, MarketParams, Token, Position, Holding,
  User, Vault, VaultConfig, VaultMarketAllocation, VaultMarketConfig,
  VaultMarketPublicAllocatorConfig, VaultUser).
- src/fetch/MarketParams.test.ts: cache-hit returns cached MarketParams,
  cache-miss path uses createMockClient + mockRead with the canonical
  morpho address from chain registry.

Existing fork-based test/* files untouched.

Verification:
- pnpm test --project blue-sdk-viem --run packages/blue-sdk-viem/src
  -> 4 files, 38 tests pass.
- pnpm --filter @morpho-org/blue-sdk-viem build succeeds.
- find packages/blue-sdk-viem/lib -name "*.test.*" -> empty.

Out of scope for this PR: MetaMorphoAction.ts (332 LOC of encoders)
and the full fetch/queries surface — extensive ABI round-trip tests
can land in follow-ups.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(liquidation-sdk-viem): phase 8 — colocated tests for thresholds, helpers, sky, 1inch

Implements TIB-2026-04-27 phase 8.

Config:
- vitest.config.ts: union liquidation-sdk-viem project include with
  src/**/*.test.ts.
- packages/liquidation-sdk-viem/tsconfig.build.{cjs,esm}.json: exclude
  src/**/*.test.ts and __test-utils__/ from emitted lib/.

Tests (33 pass):
- src/thresholds.test.ts: collateralUsdThreshold values across the
  four chains.
- src/preLiquidation/helpers.test.ts: parseWithBigInt (trailing-n
  conversion, negatives, arrays, nested objects, non-matching strings).
- src/swap/1inch.test.ts: URL builders, fetchSwap end-to-end via nock
  (200 success path, slippage bps -> percentage conversion,
  Authorization header, error path on 5xx, null/undefined param skipping).
- src/tokens/sky.test.ts: getAlternativeToken (4 token pairs +
  unsupported throw), isTokenPair (both directions, missing inputs,
  unrelated pairs), isSkyToken, getConversionFunction (4 directions
  + unsupported throw).

Existing test/* fork-based tests untouched.

Verification:
- pnpm test --project liquidation-sdk-viem --run packages/liquidation-sdk-viem/src
  -> 4 files, 33 tests pass.
- pnpm --filter @morpho-org/liquidation-sdk-viem build succeeds.
- find packages/liquidation-sdk-viem/lib -name "*.test.*" -> empty.

Out of scope for this PR: LiquidationEncoder.ts (1,001 LOC), the
swap/paraswap.ts and flashbots.ts paths, and the full token-specific
encoders (midas, pendle, spectra). These can land in follow-ups now
that the canonical nock pattern is established.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(morpho-test): sort imports in tokens.test.ts to satisfy biome 2.4.14

Biome 2.4.14 (bumped on main in #583) enforces stricter import sorting.
The CI lint job failed with `assist/source/organizeImports` on
packages/morpho-test/src/fixtures/tokens.test.ts.

Auto-fixed via `biome check --write` — single-character reorder of
the named imports from "@morpho-org/blue-sdk" so that addressesRegistry
precedes ChainId alphabetically.

Verification:
- pnpm lint -> no errors (2 unrelated warnings on codegen.ts and
  1 info on anvil.ts pre-date this branch).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(morpho-sdk): phase 9 — extend TIB scope to morpho-sdk + evm-simulation

Two packages added on main after the TIB was authored: morpho-sdk
(1.1.0, the new flagship transaction-builder package featured in
README via #581) and evm-simulation (1.0.0). Neither was in the
original in-scope list because neither existed yet.

Audit results:
- evm-simulation: already at 94.77% line coverage with 18 colocated
  .spec.ts files; tsconfig.build.{cjs,esm}.json already excludes
  *.spec.ts/*.test.ts/test-helpers/. No test work needed.
- morpho-sdk: already practices colocation (24 src + 24 test/) with
  tsconfig.build.{cjs,esm}.json excluding *.test.ts. Most colocated
  tests are fork-bound (import test/setup.ts which validates
  MAINNET_RPC_URL). Three pure-helper files lacked tests entirely.

New tests in morpho-sdk (18 pass, no fork required):
- src/helpers/constant.test.ts: MAX_SLIPPAGE_TOLERANCE,
  DEFAULT_LLTV_BUFFER, MAX_ABSOLUTE_SHARE_PRICE invariants.
- src/helpers/encodeDeallocation.test.ts: encodeForceDeallocateCall
  round-trip via decodeFunctionData/decodeAbiParameters for both
  adapter shapes (with/without marketParams); error path on
  non-positive amounts.
- src/helpers/metadata.test.ts: addTransactionMetadata empty-data
  short-circuit, timestamp append, raw-hex origin append, 0x-prefixed
  origin rejection (current implementation behavior),
  warn-on-invalid-origin, to/value preservation, combined
  timestamp + origin layout.

TIB updates:
- Scope row extended to include morpho-sdk and evm-simulation.
- New "Addenda" section dated 2026-05-04 documenting the audit,
  the decision to extend scope, and the new tests under this PR.

Also updates fixtures.test.ts (Phase 2) to compare account.address
directly against EIP-55 checksums after the lint:address script
rewrote string literals to checksum form.

Verification:
- pnpm test --project morpho-sdk --run packages/morpho-sdk/src/helpers
  -> 18 tests pass.
- pnpm --filter @morpho-org/morpho-sdk build succeeds.
- find packages/morpho-sdk/lib -name "*.test.*" -> empty.
- pnpm lint -> no errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(tibs): add post-implementation coverage report addendum

Runs pnpm test:coverage across all 10 in-scope projects (with
--coverage.reportOnFailure so fork tests that fail locally on
rate-limited RPC still contribute), merges lcov, and records the
per-package numbers as a second 2026-05-04 addendum to TIB-2026-04-27.

Highlights:
- Combined: 914 tests pass, 43.76% statements / 36.39% branches /
  47.43% functions / 44.07% lines (repo-wide denominator).
- morpho-ts 96.32% (+17.72 pp), blue-sdk 80.76% (+11.86 pp),
  blue-sdk-viem 61.77% (+5.01 pp), bundler-sdk-viem 35.89% (+0.62 pp),
  evm-simulation 94.77% (already on target).
- Notes the apparent regression in liquidity-sdk-viem and
  liquidation-sdk-viem: their denominators shrank because the new
  coverage excludes (index.ts barrels, abis.ts, api/{sdk,types}.ts)
  removed generated/re-export code from the report — exactly what
  the TIB's "exclude generated files" recommendation called for.
- Lists the files that moved from 0% in the baseline to >=90% after
  Phases 1-9 (utils, urls, format/array, format/string, AssetBalances,
  ExchangeRateWrappedToken, VaultUser, MathLib, SharesMath,
  AdaptiveCurveIrmLib, errors, preLiquidation).
- Acknowledges files still at 0% locally (LiquidationEncoder,
  MetaMorphoAction, morpho-sdk actions/entities) which CI fork tests
  are expected to cover.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test: phase 10 — MetaMorphoAction encoders, MarketUtils gaps, flashbots

Implements Phase 10 of TIB-2026-04-27. Targets the most tractable
remaining surface from each phase's "Out of scope" list — pure
encoders and pure-math helpers — without trying to reach the very
largest deferred files (LiquidationEncoder 1,001 LOC, BundlerAction
2,346 LOC, marketV1 1,071 LOC), which warrant their own TIB.

New tests (52 pass):
- packages/blue-sdk-viem/src/MetaMorphoAction.test.ts (27 tests):
  every public encoder round-tripped via decodeFunctionData -
  configuration (curator, allocator, fee recipient, skim recipient,
  fee), timelock (submit/accept/revoke), supply cap, forced market
  removal, guardian, management (skim, supply queue, withdraw queue,
  reallocate), ERC4626 (mint, deposit, withdraw, redeem). Plus
  selector-uniqueness and shape invariants.
- packages/blue-sdk/src/market/MarketUtils.test.ts (22 tests):
  getUtilization (every branch), getCollateralPower, getCollateral-
  Value (incl. missing-price), getMaxBorrowAssets, toSupplyAssets/
  toSupplyShares rounding, getAccruedInterest (zero-elapsed,
  zero-fee, realistic-rate non-zero), rateToApy.
- packages/liquidation-sdk-viem/src/flashbots.test.ts (3 tests):
  sendRawBundle posts eth_sendBundle JSON-RPC body to the relay
  with target block hex-encoded and X-Flashbots-Signature header
  set. signBundle is intentionally not unit-tested - documented
  inline why (viem/actions ESM spy limitation).

Coverage delta (per-package line):
- blue-sdk-viem: 61.77% -> 67.85% (+6.08 pp from MetaMorphoAction)
- blue-sdk: 80.76% -> 80.98% (+0.22 pp)
- liquidation-sdk-viem: 18.86% -> 19.71% (+0.85 pp)
- Combined: 44.07% -> 44.56% lines, +52 tests (914 -> 966)

MetaMorphoAction.ts notable: 332 LOC at 0% in the original TIB
baseline, now effectively fully covered on the encoder surface.

TIB updated with a Phase 10 addendum dated 2026-05-04 documenting
the coverage delta and out-of-scope follow-ups.

Verification:
- All 52 new tests pass.
- pnpm --filter @morpho-org/blue-sdk-viem
       --filter @morpho-org/blue-sdk
       --filter @morpho-org/liquidation-sdk-viem build succeeds.
- find lib -name "*.test.*" -> empty in all three packages.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: address PR review findings

Applied fixes for 4 unresolved review threads on #596:

1. mock.ts: disambiguate overloaded ABI functions in mockRead (Codex P2).
   Build the set of selectors for every same-named view/pure ABI entry
   instead of selecting only the first match by name. Read interception
   now compares the call's 4-byte selector against the full set, so reads
   against contracts with overloaded view methods no longer silently miss.
   Adds a colocated test for the overload case.

2. AGENTS.md: carve out transport-level mocks for unit tests (Devin).
   The original §2.6 / §5 ban on "mocked viem clients on RPC paths" was
   intended to forbid integration tests that fake contract behaviour.
   Per TIB-2026-04-27 (this PR), unit tests for non-fork-bound logic may
   inject createMockClient from @morpho-org/test/mock — it installs a
   vi.fn-backed custom() transport, the same surface viem/actions reads
   from, so the mock is behaviour-faithful. Anvil forks remain mandatory
   for end-to-end contract verification. AGENTS.md now reflects this.

3. .changeset/test-mock-subexport.md: minor bump for @morpho-org/test
   (Devin). Adding ./mock sub-export is additive surface; documented per
   AGENTS.md §2.10.

4. mock.ts: add @param/@returns/@throws JSDoc tags to createMockClient,
   mockRead, expectReadCall (Devin). Aligns with AGENTS.md §6 required-
   tags rule.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: remove changeset for ./mock sub-export

The new @morpho-org/test/mock sub-export is consumed only by internal
test code in this monorepo (not by external published consumers), and
the publish flow gates on changesets separately at release time. The
changeset added in 47f2e26 was unnecessary noise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: address local review findings (round 2)

Applied fixes for the local-review findings on top of the previous
round of PR-review fixes:

mock.ts public surface:
- Drop the `as unknown as chain` default; require an explicit chain
  arg so chainId-validation tests can never drift.
- Replace `as Parameters<typeof encodeFunctionResult>[0]` with viem's
  EncodeFunctionResultParameters generic.
- Rewrite the dispatch as a flat Map<address|selector, encoded result>
  on the handle (no more unbounded closure chain).
- Move eth_call dispatch into createMockClient itself; mockRead now
  just registers entries in the shared map.
- Let decodeFunctionData errors bubble in expectReadCall (single-pass
  flatMap, no swallowed exceptions).
- Add @example blocks on createMockClient, mockRead, expectReadCall
  (per AGENTS.md §6).
- Document the eth_call-only scope and the "missing other RPC methods
  fall through to default handler" behaviour.

Test files using createMockClient:
- packages/test/src/mock.test.ts: pass mainnet explicitly; add a
  mixed-mutability overload test pinning the runtime filter behaviour;
  fix stale "safeTransferFrom" comment.
- packages/blue-sdk-viem/src/fetch/MarketParams.test.ts: drop dead
  mockRead at arbitrary address; pass mainnet; tighten test name.
- packages/liquidity-sdk-viem/src/loader.test.ts: pass mainnet;
  replace silent-rejection swallow with `.rejects.toThrow()`.
- packages/bundler-sdk-viem/src/ActionBundle.test.ts: drop `null!`
  placeholders + `as never` client; use a typed nativeTransfer action
  and a real createMockClient handle.

Source bug fix:
- packages/morpho-sdk/src/helpers/metadata.ts: the regex
  `/^(?!0x)/` was a no-op (zero-width negative-lookahead replaced an
  empty match with empty). Fix to `/^0x/` so a `0x`-prefixed origin
  is normalized correctly. Update colocated test to match: 0xcafe
  now appends 'cafe' to the calldata; new tests cover
  timestamp = false explicit, raw-hex length-check (separate from
  isHex), and 0x-prefixed length-check.

Other test improvements:
- preLiquidation.test.ts: add expect.fail() guard so the bare try/
  catch can no longer silently green if getDefaultPreLiquidationParams
  stops throwing.
- bundler-sdk-viem/errors.test.ts: assert by class identity, not
  message string (per AGENTS.md §5).
- blue-sdk-viem/augment/augment.test.ts: replace `typeof X.fetch ===
  "function"` with `expect(X.fetch).toBe(fetchX)` identity assertions
  for all 12 augmented classes — catches regressions that wire fetch
  to the wrong function.
- liquidation-sdk-viem/flashbots.test.ts: switch to testAccount() per
  packages/test/CLAUDE.md; recover the signature header to verify
  it's a real signMessage of the body keccak; pin blockNumber as a
  hex literal; assert nock.isDone().
- liquidation-sdk-viem/swap/1inch.test.ts: pin error class on 5xx;
  add coverage for non-numeric slippage (NaN encoding) and missing
  API key ('Bearer undefined' header) — both pin current behaviour.
- blue-sdk/math/MathLib.test.ts: add maxUint(0) boundary and
  zeroFloorSub with negative y.
- morpho-ts/utils.test.ts: bigIntComparator now covers null/null,
  undefined/undefined, and mixed nullish.
- Drop mutability-only tests from User.test.ts, VaultUser.test.ts,
  VaultMarketPublicAllocatorConfig.test.ts (they only verified the
  TypeScript type is mutable, not behaviour).

TIB and AGENTS.md:
- TIB Status: Proposed -> Accepted.
- TIB References: drop "(to be migrated)" parenthetical that
  contradicted Convention 4.
- TIB addendum heading: "Coverage after implementation" -> "Coverage
  after Phases 1-9" (Phase 10 has its own addendum).
- TIB addendum: drop stale colocated-test-count (changes per phase).

Verification:
- 548 colocated tests pass across 42 files.
- pnpm lint passes (no errors; pre-existing warnings on codegen.ts /
  anvil.ts from biome 2.4.14 are unchanged).
- pnpm --filter <every touched package> build succeeds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: address local review findings (round 3)

- Restore changeset for the @morpho-org/test ./mock sub-export
- Add changeset for addTransactionMetadata 0x-prefix-origin behavioural change
- mock.ts: tighten JSDoc on dispatch key format and mockRead checksum
  semantics; pre-filter expectReadCall by selector set so unrelated calls
  to the same address don't abort decode iteration
- mock.test.ts: strengthen "non-view/pure overload" test to actually assert
  the permissive runtime registers nonpayable selectors too
- MetaMorphoAction.test.ts: add inline-snapshot pinning for security-critical
  setters (setCurator/setFee/setFeeRecipient/setIsAllocator/submitGuardian/
  acceptGuardian/submitCap/acceptCap/submitMarketRemoval); use vitest 4
  test-context expect to avoid shadowing
- augment.test.ts: split single 12-expect block into test.each with one row
  per wiring; cover AccrualPosition.fetch, fetchPreLiquidation, AccrualVault.fetch
- ActionBundle.test.ts: hoist dynamic imports of @morpho-org/test/mock and
  viem/chains to top of file
- 1inch.test.ts: replace process.env mutation with vi.stubEnv +
  vi.unstubAllEnvs in afterEach (concurrent-safe)
- flashbots.test.ts: add explicit length check on split(":") before destructure
- Pin error classes across .toThrow() sites (InvalidAddressError, ClientError,
  SyntaxError, TypeError) instead of bare .toThrow()
- loader.test.ts: tighten reject message regex
- metadata.ts: extend JSDoc with 0x-prefix normalization rules
- AGENTS.md §2.6: broaden mock-allowed scope wording with explicit list of
  fork-only paths (oracles, accruals, deployless, contract-revert)
- TIB §Convention 2: replace stale pre-shipped API code block

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: address local review (round 4) — concurrent-test safety + JSDoc

HIGH — concurrent-mode races on process-global state:

- flashbots.test.ts, 1inch.test.ts, liquidity-sdk-viem/api/index.test.ts:
  convert nock-using describes to `describe.sequential`. Under the repo
  default `sequence: { concurrent: true }`, `afterEach(nock.cleanAll)`
  would wipe other in-flight tests' interceptors. 1inch.test.ts also
  had `vi.stubEnv` / `vi.unstubAllEnvs` racing on process.env.

MEDIUM — same class of race on other globals:

- metadata.test.ts: `vi.spyOn(console, "warn")` across 3 tests — last
  spy wins, restoreAllMocks revokes mid-flight. Sequentialize.
- locale.test.ts: `vi.stubGlobal("window"|"navigator"|"document")`
  across 4 tests — same hazard. Sequentialize.

LOW — JSDoc clarity in `@morpho-org/test/mock`:

- mock.ts: tighten `MockClientHandle.dispatch` concurrency note to
  describe the actual race (`(addr, selector)` overwrite, mid-flight
  `dispatch.clear`) instead of a non-existent "different key format".
- mock.ts: move `createMockClient`'s @throws into @remarks — the
  factory itself never throws; the throw happens at later transport
  call time, which @throws conventionally doesn't document on factories.
- mock.test.ts: convert tautological "round-trip" test to actually
  decode the returned ABI-encoded result via `decodeFunctionResult`
  and assert the registered value (42n) comes back. Previous version
  decoded a separately re-encoded call and asserted `result.startsWith("0x")`,
  which would pass on any hex string.

Verified: all touched tests still pass under `CI=true pnpm vitest run`.
Pre-existing fork-test failures (MAINNET_RPC_URL required) are unrelated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: drop ambiguous test count from locale.test.ts comment

The describe.sequential comment said "the four tests below call
vi.stubGlobal" but the describe contains 5 tests. Only 4 actually
call stubGlobal; the first test asserts on the un-stubbed window
global and also benefits from sequencing. Drop the count to avoid
the off-by-one and clarify both reasons for serializing the describe.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: address Codex P2 review on @morpho-org/test/mock

Two Codex P2 findings on PR #596:

1. mockRead encodes per-overload (was: once, then reused for every
   overload selector). For ABIs whose same-named overloads have
   different return types, the previous behaviour stored bytes
   encoded against the wrong output ABI under the other selectors,
   producing wrong values at decode time. Now: try-encode each
   overload's single-item ABI; register only selectors where
   encoding succeeds. Throw if the supplied result matches no
   overload's return shape (clear signal for the caller). Behaviour
   is unchanged when overloads share a return type. Added test
   coverage for the different-return-type case.

2. Drop the CJS `require` condition for ./mock from
   publishConfig.exports + exclude mock.ts from the CJS build.
   mock.ts imports vitest at the top level and vitest rejects
   require() ("Vitest cannot be imported in a CommonJS module
   using require()"). The ESM entry is the only legitimate
   consumer surface for this subpath (vitest is ESM-only).

Changeset documents both as a patch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(changeset): reframe ./mock changeset around mockRead behaviour change

The changeset existed because of two changes shipped in b0d12e1:
1. mockRead now encodes per-overload (behavioural change to a public
   exported function — does warrant a patch changeset).
2. ./mock CJS condition removed from publishConfig.exports — packaging
   metadata catching up to reality (the entry was crash-on-load via
   vitest's require() rejection; no working consumer is affected).

Per AGENTS.md §7 the packaging cleanup alone wouldn't merit a
changeset. Rewrite to lead with the mockRead behaviour change and
relegate the CJS removal to a drive-by note.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: address Rubilmax PR review (round 5)

10 unresolved threads from human review:

Source changes:
- metadata.ts: strip leading 0x/0X case-insensitively (was: lowercase only,
  silently dropped "0Xcafe"). Add even-length guard on the raw fragment —
  odd-nibble origin would otherwise pad at concatHex broadcast time and
  corrupt the trailing analytics byte. Both regressions widened by the
  round-2 0x-strip fix.
- mock.ts JSDoc: align @throws to canonical {ErrorClass} syntax per
  docs/jsdoc-style.md §5. Rewrite expectReadCall's @example as a
  self-contained runnable snippet with real fixture addresses (USDC +
  dead-address) instead of "0x..." placeholders. Add a return-type note
  documenting that decoded args are a union over the whole abi rather
  than narrowed to functionName. Update the stale "decode errors bubble"
  paragraph — the round-3 selector pre-filter makes mismatched-ABI calls
  return [] instead of throwing.

Test additions:
- error.test.ts: cover getUnsupportedVaultV2Adapter (5 cases incl. nested
  cause walk + missing args) and the 3 untested permit-domain error
  classes (field preservation + message format + edge cases).
- metadata.test.ts: 0X-prefix accepted; odd-length raw + 0x-prefixed
  fragments rejected with warn.
- encodeDeallocation.test.ts: actually assert the error message contains
  the adapter address (test title previously misleading).
- mock.test.ts: malformed eth_call (missing to/data) falls through to
  unhandled-RPC; unrelated-call filtering pinned; wrong-arity ABI now
  returns [] (no decode-throw) as documented above.
- flashbots.test.ts: cover the !response.ok 5xx branch using explicit
  application/json content-type (Rubilmax's suggested approach).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

2 participants