Skip to content

Conversation

@samholmes
Copy link
Contributor

@samholmes samholmes commented Jan 20, 2026

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

Description

none

Note

Introduces structured logging and flexible auth plus transport improvements, with targeted plugin updates and stronger scans.

  • Logging: Replace ad hoc console logs with Pino-based JSON logs via makeLogger, adding scoped (server, socket, blockbook, evmRpc) and IP/sockeId context; add docs/logging.md; update server/hub for connection/subscription/update/close/error events.
  • Auth + URL templating: Add serviceKeys config and authenticateUrl with {{apiKey}} replacement and flexible host matching; remove nowNodesApiKey; use templated URLs in Blockbook and EVM RPC plugins.
  • evmRpc transports: Support both HTTP and WebSocket via dynamic transport selection; improve block processing logs, ERC20 getLogs retries, internal transfer tracing, and scanAddress adapter fallback/shuffle.
  • Scan adapters: Rework Etherscan V1/V2 adapters to use serviceKeysFromUrl, robust JSON cleaning, rate-limit backoff/retries, and startblock = checkpoint + 1.
  • Plugins: Trim plugin list to reduce load; keep core networks (BTC family, Ethereum, BSC, Optimism, Polygon, zkSync, Botanix) with authenticated endpoints.
  • Tests/infra: Update tests for new logging, URL templating, hub IP handling; add pino dependency and minor utilities (addressUtils, serviceKeys, replaceUrlParams).

Written by Cursor Bugbot for commit 24d80de. This will update automatically on new commits. Configure here.


- Use Pino for performant logging
- Use Pino's .child() pattern for efficient scoped logging
- Add pino-pretty support for human-readable development output
- Disable logging in tests via NODE_ENV check
- Automatically rename conflicting fields (time → time_, scope → scope_)
Remove the following plugins to reduce load:
- abstract, amoy, arbitrum, avalanche, base
- bobevm, celo, ethereumclassic, ethereumpow, fantom
- filecoinfevm, filecoinfevmcalibration, holesky, hyperevm
- pulsechain, rsk, sepolia, sonic
Add serviceKeysFromUrl utility that matches API keys to URLs by hostname
with subdomain fallback support (e.g., api.example.com → example.com).
Keys can be configured with or without ports.

- Add src/util/serviceKeys.ts with ServiceKeys type and matching logic
- Add src/util/replaceUrlParams.ts for {{param}} placeholder substitution
- Add src/util/authenticateUrl.ts to combine key lookup with URL templating
- Add comprehensive tests for serviceKeysFromUrl

Refactor RPC and scan adapter configuration:
- Switch to authenticated RPC endpoints using {{apiKey}} templates
- Make scanAdapters required in EvmRpcOptions
- Update EtherscanV1/V2 adapters to use serviceKeysFromUrl
- Fix pickRandom return type to T | undefined for empty arrays
- Improve error handling when no URLs or API keys are configured
This reduces complexity and re-uses the new infrastructure.

The only trade-off is to remove the logging of the URL without the
key, which we can accept since these logs should be treated as
company sensitive.
Add txlistinternal action to EtherscanV1ScanAdapter for parity with V2.
This enables detection of contract-to-contract calls that were previously
missed by the V1 adapter.
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 3 potential issues.

.then(result => {
if (result.subscribed) {
logger.log('Block connection initialized')
logger.info({ scope: 'foo' }, 'Block connection initialized')
Copy link

Choose a reason for hiding this comment

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

Accidentally committed debug value in logger call

Medium Severity

The log call passes { scope: 'foo' } which appears to be leftover debug code. The scope field is reserved by the logger (as documented in logger.ts), and the value 'foo' is clearly a placeholder. This will cause the log output to include a warning field about the reserved scope field being overwritten, resulting in confusing log messages like "Warning: 'scope' field because it's reserved for logging context": "foo".

Fix in Cursor Fix in Web

// Shuffles array and returns a new array.
export const shuffleArray = <T>(array: T[]): T[] => {
return array.sort(() => Math.random() - 0.5)
}
Copy link

Choose a reason for hiding this comment

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

shuffleArray mutates original array despite documentation

Medium Severity

The shuffleArray function's comment states it "returns a new array," but Array.sort() mutates the original array in place and returns a reference to the same array. In evmRpc.ts, this means scanAdapters (from the plugin options) is mutated on every call to scanAddress, potentially causing unexpected side effects if the configuration is shared or inspected elsewhere.

Additional Locations (1)

Fix in Cursor Fix in Web

const apiKey = apiKeys == null ? undefined : pickRandom(apiKeys)
if (apiKey != null) {
params.set('apikey', apiKey)
}
Copy link

Choose a reason for hiding this comment

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

API key persists across retry attempts to different URLs

Medium Severity

In the retry loop, the code only sets params.set('apikey', apiKey) when an API key is found, but doesn't remove the key when one isn't found. Since serviceKeysFromUrl returns an empty array (not null) when no keys exist, pickRandom([]) returns undefined, and the conditional if (apiKey != null) fails without clearing the previous key. If a retry picks a different URL with no configured API key, the previous iteration's API key remains in params and gets sent to the wrong service.

Additional Locations (1)

Fix in Cursor Fix in Web

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