Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions intentkit/utils/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,14 @@ class NetworkId(IntEnum):
BeraMainnet = 80094


# QuickNode may return short chain/network identifiers that map to existing enums.
QUICKNODE_CHAIN_ALIASES: dict[str, str] = {
"arb": Chain.Arbitrum.value,
}
QUICKNODE_NETWORK_ALIASES: dict[str, str] = {
"optimism": QuickNodeNetwork.OptimismMainnet.value,
}

# Mapping of QuickNodeNetwork enum members to their corresponding NetworkId enum members.
# This dictionary facilitates efficient lookup of network IDs given a network name.
# Note: SolanaMainnet is intentionally excluded as it does not have a numeric chain ID.
Expand Down Expand Up @@ -517,9 +525,13 @@ def init_chain_configs(self, limit: int = 100, offset: int = 0) -> None:
continue

try:
chain_value = item["chain"]
network_value = item["network"]
chain_value = str(item["chain"]).lower()
network_value = str(item["network"]).lower()
rpc_url = item["http_url"]
chain_value = QUICKNODE_CHAIN_ALIASES.get(chain_value, chain_value)
network_value = QUICKNODE_NETWORK_ALIASES.get(
network_value, network_value
)
chain = Chain(chain_value)
network = QuickNodeNetwork(network_value)
ens_url = item.get("ens_url", rpc_url)
Expand Down
55 changes: 55 additions & 0 deletions tests/utils/test_chain.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import pytest

import intentkit.utils.chain as chain_utils
from intentkit.utils.chain import (
Chain,
ChainConfig,
ChainProvider,
NetworkId,
QuicknodeChainProvider,
QuickNodeNetwork,
)

Expand All @@ -26,6 +28,31 @@ def init_chain_configs(self, api_key: str = ""):
self.api_key = api_key


class DummyResponse:
def __init__(self, payload: dict[str, list[dict[str, str]]]):
self._payload = payload

def raise_for_status(self) -> None:
return None

def json(self) -> dict[str, list[dict[str, str]]]:
return self._payload


class DummyClient:
def __init__(self, payload: dict[str, list[dict[str, str]]]):
self._payload = payload

def __enter__(self) -> "DummyClient":
return self

def __exit__(self, exc_type, exc, traceback) -> None:
return None

def get(self, *_, **__) -> DummyResponse:
return DummyResponse(self._payload)


def test_chain_config_properties():
config = ChainConfig(
chain=Chain.Ethereum,
Expand Down Expand Up @@ -53,6 +80,34 @@ def test_chain_provider_fetch_by_network_and_id():
assert config_by_id is config


def test_quicknode_chain_provider_alias_mapping(monkeypatch: pytest.MonkeyPatch):
# QuickNode can return chain "arb" with network "optimism"; both should map.
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The comment states "QuickNode can return chain 'arb' with network 'optimism'" but this is misleading. According to the PR description, QuickNode returns chain='arb' with network='arbitrum-mainnet' for Arbitrum, and chain='optimism' with network='optimism' for Optimism. The comment should accurately describe what the test is validating.

Suggested change
# QuickNode can return chain "arb" with network "optimism"; both should map.
# Simulate QuickNode returning chain "arb" with network "optimism" and verify both aliases map correctly.

Copilot uses AI. Check for mistakes.
payload = {
"data": [
{
"chain": "arb",
"network": "optimism",
"http_url": "https://quicknode",
"ens_url": "https://ens",
"wss_url": "wss://quicknode",
}
]
}

monkeypatch.setattr(
chain_utils.httpx,
"Client",
lambda *_, **__: DummyClient(payload),
)

provider = QuicknodeChainProvider("test-key")
provider.init_chain_configs()

config = provider.chain_configs[QuickNodeNetwork.OptimismMainnet]
assert config.chain is Chain.Arbitrum
assert config.network is QuickNodeNetwork.OptimismMainnet
Comment on lines +83 to +108
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The test uses an unrealistic combination of QuickNode identifiers. According to the PR description, QuickNode returns:

  • chain='arb', network='arbitrum-mainnet' for Arbitrum endpoints
  • chain='optimism', network='optimism' for Optimism endpoints

This test combines chain='arb' with network='optimism', which doesn't represent an actual QuickNode response. While the test technically validates that both aliases work, it doesn't test the real-world scenarios that were causing the startup errors. Consider adding separate test cases for each actual QuickNode response pattern.

Copilot uses AI. Check for mistakes.


def test_chain_provider_missing_network():
provider = DummyChainProvider()

Expand Down
Loading