Skip to content

[BCN] Multi Provider With Alchemy Adapter#4111

Open
leolambo wants to merge 13 commits intobitpay:masterfrom
leolambo:multiProviderAlchemy
Open

[BCN] Multi Provider With Alchemy Adapter#4111
leolambo wants to merge 13 commits intobitpay:masterfrom
leolambo:multiProviderAlchemy

Conversation

@leolambo
Copy link
Contributor

@leolambo leolambo commented Feb 24, 2026

Description

Add multi-provider external chain state adapter with Alchemy integration, enabling failover between multiple indexed API providers for EVM chains.

Follow-up:

Moralis Adapter, API streaming improvements, Integration tests

Changelog

  • Add adapter error taxonomy with health-affecting classification
  • Add provider health tracker using consecutive-failure counter and cooldown
  • Add IIndexedAPIAdapter interface, config types, and AdapterFactory
  • Add AlchemyAdapter with asset transfer stream
  • Add multi-provider chain state provider with round-robin failover and block-time caching
  • Align provider config with Moralis patterns (dynamic URL resolution, isBreakerableaffectsHealth)

Testing Notes

cd packages/bitcore-node && npm run tests

Checklist

  • I have read CONTRIBUTING.md and verified that this PR follows the guidelines and requirements outlined in it.
  • I have added the appropriate package tag(s) (e.g. BWC if modifying the bitcore-wallet-client package, CLI if modifying the bitcore-cli package, etc.)
  • I have verified that this is not an existing PR (open or closed)

Replace the circuit breaker state machine with a simpler
consecutive-failure counter and cooldown approach.
N failures in a row, skip for M seconds, then retry.
- Fix getBlockBeforeTime signature to match
  GetBlockBeforeTimeParams
- Fix AlchemyAssetTransferStream field collision
  with base class
- Fix blockHeight possibly undefined in confirmation
- Remove unused imports and dead code
- Cast test args as any to satisfy type constraints
- Add operational logging to csp.ts (stream lifecycle,
  failover events, block-by-date resolution)
- Rename _enforceFloorSemantics to _verifyBlockBeforeDate
- Rename IProviderConfig to IMultiProviderConfig with
  only health/priority/timeout fields
- Move apiKey to global config.externalProviders.alchemy
  (matches Moralis pattern)
- Resolve Alchemy URLs dynamically per-call via
  ALCHEMY_NETWORK_MAP
- Add chain/network to AdapterBlockByDateParams for
  dynamic URL resolution
- Add blockAtTimeCache (LRU per chain:network) to
  multi-provider CSP
- Rename isBreakerable to affectsHealth across error
  taxonomy
- Update all tests (47 passing)
@kajoseph kajoseph added the BCN This pull request modifies the bitcore-node package label Feb 27, 2026
Copy link
Collaborator

@kajoseph kajoseph left a comment

Choose a reason for hiding this comment

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

Lots of lint errors, particularly with imports. Make sure you have the eslint extension installed and you may need to clear all your node_modules:

npx lerna exec rm -rf node_modules

Still functionally testing, but so far this is looking good!

mtSyncTipPad?: number; // Default: 100. Multi-threaded sync will sync up to latest block height minus mtSyncTipPad. MT syncing is blind to reorgs. This helps ensure reorgs are accounted for near the tip.
leanTransactionStorage?: boolean; // Removes data, abiType, internal and calls before saving a transaction to the databases
needsL1Fee?: boolean; // Does this chain require a layer-1 fee to be added to a transaction (e.g. OP-stack chains)?
externalProviders?: IMultiProviderConfig[];
Copy link
Collaborator

Choose a reason for hiding this comment

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

is this type correct? I added to my config per this file and am getting a startup error.

bitcore.config.json:

      ...
      "MATIC": {
        "mainnet": {
          ...
          "externalProviders": [{
            "name": "alchemy",
            "priority": 0
          }]

error:

Unhandled Rejection at: Error: AlchemyAdapter: apiKey is required in config.externalProviders.alchemy
    at new AlchemyAdapter (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/providers/chain-state/external/adapters/alchemy.ts:37:24)
    at Function.createAdapter (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/providers/chain-state/external/adapters/factory.ts:18:12)
    at /home/kjoseph/dev/bitcore/packages/bitcore-node/src/modules/multiProvider/api/csp.ts:62:35
    at Array.map (<anonymous>)
    at MultiProviderEVMStateProvider.initializeProviders (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/modules/multiProvider/api/csp.ts:61:10)
    at new MultiProviderEVMStateProvider (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/modules/multiProvider/api/csp.ts:40:10)
    at new MultiProviderModule (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/modules/multiProvider/index.ts:22:17)
    at ModuleManager.loadConfigured (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/modules/index.ts:80:36)
    at ClusteredApiWorker (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/workers/api.ts:34:11)
    at Object.<anonymous> (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/workers/api.ts:66:21)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Well, I updated my config to fix that error, but now it's giving me another.

bitcore.config.json:

      ...
      "MATIC": {
        "mainnet": {
          ...
          "externalProviders": {
            "alchemy": {
              "apiKey": ""
            }
          }

error:

Unhandled Rejection at: TypeError: externalProviders.map is not a function
    at MultiProviderEVMStateProvider.initializeProviders (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/modules/multiProvider/api/csp.ts:61:10)
    at new MultiProviderEVMStateProvider (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/modules/multiProvider/api/csp.ts:40:10)
    at new MultiProviderModule (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/modules/multiProvider/index.ts:22:17)
    at ModuleManager.loadConfigured (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/modules/index.ts:80:36)
    at ClusteredApiWorker (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/workers/api.ts:34:11)
    at Object.<anonymous> (/home/kjoseph/dev/bitcore/packages/bitcore-node/src/workers/api.ts:66:21)
    at Module._compile (node:internal/modules/cjs/loader:1730:14)
    at Object..js (node:internal/modules/cjs/loader:1895:10)
    at Module.load (node:internal/modules/cjs/loader:1465:32)
    at Function._load (node:internal/modules/cjs/loader:1282:12)

I'm confused about how this externalProviders field is supposed to look. One error makes it seems like it's supposed to be a map, the other suggest an array.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nevermind - this was a lot of noise for nothing. I figured it out.

Copy link
Collaborator

Choose a reason for hiding this comment

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

If anything's to be taken away from this, it's that having a field named "externalProviders" in two different places in the config can be confusing - especially when they're both needed when using the multi provider. Just 2c

Separate per-network routing order from provider credentials.
The externalProviders key at the config root now holds only API
keys, while indexedProviderRouting defines the priority-ordered
adapter list per network.
BigInt values from external providers can exceed
Number.MAX_SAFE_INTEGER, losing precision when cast to number.
Accept string alongside number in gasLimit, gasPrice, nonce,
value, and transactionIndex to preserve full precision.
Replace static ALCHEMY_NETWORK_MAP with convention-based URL
derivation so new chains need no code change. Return RPC
quantity fields as BigInt strings to avoid IEEE 754 precision
loss. Update test assertions accordingly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BCN This pull request modifies the bitcore-node package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants