From 1f0a371949dbfce77b95581ea055934d86d67d33 Mon Sep 17 00:00:00 2001 From: octo-patch Date: Tue, 21 Apr 2026 09:14:36 +0800 Subject: [PATCH] fix: use resolve_supported_network() for consistent CDP network alias mapping (fixes #723) The previous get_cdp_network() used a hardcoded string mapping that only accepted canonical network IDs (e.g., "base-mainnet", "ethereum-mainnet"). This diverged from AGENT_NETWORK_TO_SUPPORTED_NETWORK in chain.py, which supports additional aliases like "ethereum", "polygon", "matic", "bsc-mainnet", and "binance-mainnet". Now get_cdp_network() calls resolve_supported_network() first to normalize the input, then looks up the CDP network name via SupportedNetwork enum. This ensures any alias supported by the chain utility is automatically honoured, preventing 400 BadNetworkID errors for valid but non-canonical network identifiers. Add tests covering canonical names, all recognized aliases, and error cases. --- intentkit/wallets/cdp.py | 29 ++++++---- tests/wallets/test_cdp_network.py | 88 +++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 tests/wallets/test_cdp_network.py diff --git a/intentkit/wallets/cdp.py b/intentkit/wallets/cdp.py index bd02290b7..3121dbb32 100644 --- a/intentkit/wallets/cdp.py +++ b/intentkit/wallets/cdp.py @@ -11,6 +11,7 @@ from intentkit.config.db import get_session from intentkit.models.agent import Agent, AgentTable from intentkit.models.agent_data import AgentData +from intentkit.utils.chain import SupportedNetwork, resolve_supported_network from intentkit.utils.error import IntentKitAPIError from intentkit.wallets.web3 import get_async_web3_client @@ -190,6 +191,17 @@ async def get_evm_account(agent: Agent) -> EvmServerAccount: return account +_SUPPORTED_NETWORK_TO_CDP: dict[SupportedNetwork, str] = { + SupportedNetwork.EthereumMainnet: "ethereum", + SupportedNetwork.BaseMainnet: "base", + SupportedNetwork.ArbitrumMainnet: "arbitrum", + SupportedNetwork.OptimismMainnet: "optimism", + SupportedNetwork.PolygonMainnet: "polygon", + SupportedNetwork.BaseSepolia: "base-sepolia", + SupportedNetwork.BnbMainnet: "bsc", +} + + def get_cdp_network(agent: Agent) -> str: if not agent.network_id: raise IntentKitAPIError( @@ -197,20 +209,17 @@ def get_cdp_network(agent: Agent) -> str: "BadNetworkID", "Your agent network ID is not set. Please set it in the agent config.", ) - mapping = { - "ethereum-mainnet": "ethereum", - "base-mainnet": "base", - "arbitrum-mainnet": "arbitrum", - "optimism-mainnet": "optimism", - "polygon-mainnet": "polygon", - "base-sepolia": "base-sepolia", - "bnb-mainnet": "bsc", - } if agent.network_id == "solana": raise IntentKitAPIError( 400, "BadNetworkID", "Solana is not supported by CDP EVM." ) - cdp_network = mapping.get(agent.network_id) + try: + supported_network = resolve_supported_network(agent.network_id) + except ValueError: + raise IntentKitAPIError( + 400, "BadNetworkID", f"Unsupported network ID: {agent.network_id}" + ) + cdp_network = _SUPPORTED_NETWORK_TO_CDP.get(supported_network) if not cdp_network: raise IntentKitAPIError( 400, "BadNetworkID", f"Unsupported network ID: {agent.network_id}" diff --git a/tests/wallets/test_cdp_network.py b/tests/wallets/test_cdp_network.py new file mode 100644 index 000000000..00075a713 --- /dev/null +++ b/tests/wallets/test_cdp_network.py @@ -0,0 +1,88 @@ +"""Tests for get_cdp_network() in intentkit/wallets/cdp.py.""" + +from types import SimpleNamespace + +import pytest + +from intentkit.utils.error import IntentKitAPIError +from intentkit.wallets.cdp import get_cdp_network + + +def _agent(network_id): + """Return a minimal agent-like object with the given network_id.""" + return SimpleNamespace(network_id=network_id) + + +class TestGetCdpNetworkCanonicalNames: + """Canonical network IDs that were already supported.""" + + def test_base_mainnet(self): + assert get_cdp_network(_agent("base-mainnet")) == "base" + + def test_ethereum_mainnet(self): + assert get_cdp_network(_agent("ethereum-mainnet")) == "ethereum" + + def test_arbitrum_mainnet(self): + assert get_cdp_network(_agent("arbitrum-mainnet")) == "arbitrum" + + def test_optimism_mainnet(self): + assert get_cdp_network(_agent("optimism-mainnet")) == "optimism" + + def test_polygon_mainnet(self): + assert get_cdp_network(_agent("polygon-mainnet")) == "polygon" + + def test_base_sepolia(self): + assert get_cdp_network(_agent("base-sepolia")) == "base-sepolia" + + def test_bnb_mainnet(self): + assert get_cdp_network(_agent("bnb-mainnet")) == "bsc" + + +class TestGetCdpNetworkAliases: + """Network aliases that resolve via AGENT_NETWORK_TO_SUPPORTED_NETWORK.""" + + def test_ethereum_alias(self): + # "ethereum" is an alias for "ethereum-mainnet" + assert get_cdp_network(_agent("ethereum")) == "ethereum" + + def test_polygon_alias(self): + # "polygon" is an alias for "polygon-mainnet" + assert get_cdp_network(_agent("polygon")) == "polygon" + + def test_matic_alias(self): + # "matic" is an alias for "polygon-mainnet" + assert get_cdp_network(_agent("matic")) == "polygon" + + def test_matic_mainnet_alias(self): + assert get_cdp_network(_agent("matic-mainnet")) == "polygon" + + def test_bsc_mainnet_alias(self): + # "bsc-mainnet" is an alias for "bnb-mainnet" + assert get_cdp_network(_agent("bsc-mainnet")) == "bsc" + + def test_binance_mainnet_alias(self): + # "binance-mainnet" is an alias for "bnb-mainnet" + assert get_cdp_network(_agent("binance-mainnet")) == "bsc" + + +class TestGetCdpNetworkErrors: + def test_missing_network_id_raises(self): + with pytest.raises(IntentKitAPIError) as exc_info: + get_cdp_network(_agent(None)) + assert exc_info.value.status_code == 400 + + def test_empty_network_id_raises(self): + with pytest.raises(IntentKitAPIError) as exc_info: + get_cdp_network(_agent("")) + assert exc_info.value.status_code == 400 + + def test_solana_raises(self): + with pytest.raises(IntentKitAPIError) as exc_info: + get_cdp_network(_agent("solana")) + assert exc_info.value.status_code == 400 + assert "Solana" in str(exc_info.value) + + def test_unknown_network_raises(self): + with pytest.raises(IntentKitAPIError) as exc_info: + get_cdp_network(_agent("not-a-real-network")) + assert exc_info.value.status_code == 400