Skip to content

fix / gateway use unified /trading endpoints and stop masking Gateway errors - #193

Merged
fengtality merged 4 commits into
mainfrom
fix/gateway-unified-endpoints
Jul 21, 2026
Merged

fix / gateway use unified /trading endpoints and stop masking Gateway errors#193
fengtality merged 4 commits into
mainfrom
fix/gateway-unified-endpoints

Conversation

@fengtality

@fengtality fengtality commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

An audit of every Gateway route used by hummingbot-api (against Gateway core-2.9 / feat-robinhood-chain running on mTLS 15888) found the swap and CLMM paths pointing at routes that don't exist, plus a class of bugs where Gateway's error responses were silently treated as data.

GatewayClient

  • Swaps use Gateway's unified /trading/swap/{quote,execute} instead of /connectors/{c}/router/*. The old path 404'd for clmm-only connectors (meteora, orca, pancakeswap-sol) and doubled the segment for typed values (jupiter/router.../router/router/quote-swap).
  • normalize_swap_connector(): bare router connectors (jupiter, 0x, uniswap, pancakeswap) get /router appended, everything else /clmm; already-typed values (meteora/clmm, raydium/amm) pass through.
  • CLMM ops use unified /trading/clmm/* with the schema Gateway actually expects: chainNetwork, walletAddress, percentageToRemove (the legacy /clmm/liquidity/* paths and address/percentage keys don't exist on Gateway).
  • New GatewayError + check_gateway_error() for the {"error", "status"} dict _request returns on non-OK responses.

Error propagation fixes

  • /gateway/swap/quote no longer renders a Gateway 404 as a 200 quote with price: "0" — Gateway errors propagate with their real status code and message.
  • _refresh_position_data no longer closes positions in the DB when positions-owned returns a Gateway error (only when the position is genuinely absent from a valid response).
  • The transaction poller treats Gateway HTTP errors as transient (retry later) instead of recording them as on-chain FAILED.
  • The gecko price source no longer caches an empty token map on Gateway errors.
  • slippage_pct=0 was dropped as falsy and replaced with the 1.0 default in several places; now uses is not None.

Gateway connector discovery

  • Start the Gateway status monitor in the app lifespan (main.py) and stop it on shutdown. GatewayHttpClient's monitor reads /config/chains when Gateway comes online and registers each network connector (e.g. solana-mainnet-beta, ethereum-mainnet, and newly added chains like ethereum-unichain) into hummingbot's AllConnectorSettings. That monitor is started by the standalone client's TradingCore but was never started here, so Gateway networks were absent from AllConnectorSettings until a connector for one happened to be constructed on demand. Startup is unaffected when Gateway is unreachable — the monitor pings in the background and simply stays offline.

Test plan

  • pytest test/test_gateway_client_contract.py test/test_gateway_error_masking.py — 32 tests pinning the paths, payload keys, and error behavior (all passing).
  • Verified live against Gateway on 15888: meteora/clmm and bare jupiter quotes return real prices; a bogus connector returns Gateway's real error instead of price 0; CLMM remove-liquidity hits /trading/clmm/remove and propagates Gateway's 404 for an unknown position; slippage_pct: 0 round-trips as "0".
  • Monitor/registration verified live: after startup, GET /connectors/ lists all Gateway networks from /config/chains; with Gateway unreachable the API still boots (200, no networks, no traceback) and picks them up on the next successful poll; clean shutdown stops the monitor without hanging.

QA — test this PR together with hummingbot #8377

These two PRs are the paired Gateway fix: #193 (this PR) fixes hummingbot-api's own Gateway REST layer + connector discovery; hummingbot #8377 makes the in-process OrderExecutor work on Gateway swaps (order sizing, skipping the BudgetChecker, unified /trading/swap/* routes, and AllConnectorSettings registration on connector start). Test them together so the full POST /executors/ → Gateway path is exercised.

Setup

  1. Gateway running with Solana mainnet-beta and a swap router (e.g. Jupiter). Add a funded Solana wallet (a few USD of SOL for the swap + gas is enough) and set it as the default. Confirm GET http://localhost:15888/config/chains lists solana.
  2. hummingbot #8377 — build a wheel from the PR branch and install it into the hummingbot-api env:
    # in a checkout of hummingbot on branch fix/gateway-memecoin-balance-validation
    python -m build --wheel --no-isolation
    pip install dist/hummingbot-*-cp312-*.whl --force-reinstall --no-deps   # into the hummingbot-api conda env
  3. hummingbot-api fix / gateway use unified /trading endpoints and stop masking Gateway errors #193 — run this branch from source:
    git checkout fix/gateway-unified-endpoints
    docker compose up emqx postgres -d
    uvicorn main:app --reload      # GATEWAY_URL in .env points at Gateway (default http://localhost:15888)

1. Connector discovery (this PR)

  • GET /connectors/ → the Gateway networks (solana-mainnet-beta, ethereum-mainnet, …) appear in the list. On development they're absent (the monitor never runs), so this is the before/after.
  • Resilience: start the API with Gateway stopped → API still returns 200 and the Gateway networks are simply absent (no crash, no hang). Start Gateway and restart → the networks appear. Adding a new chain to Gateway (e.g. unichain) makes it appear here with no code change.

2. Swap quote + error masking (this PR)

  • POST /gateway/swap/quote with { "connector": "jupiter", "network": "solana-mainnet-beta", "trading_pair": "SOL-USDC", "side": "SELL", "amount": 0.01, "slippage_pct": 1.0 } → a real price, not 0.
  • Repeat with a bogus connector → Gateway's real error propagates with its status, not a 200 price: "0".

3. End-to-end OrderExecutor on Gateway (needs #8377)

Deploy a swap executor. connector_name is the Gateway network id solana-mainnet-beta (not jupiter / jupiter/router — the unified Gateway connector resolves the swap provider and default wallet itself):

curl -u admin:admin -X POST http://localhost:8000/executors/ -H 'Content-Type: application/json' -d '{
  "account_name": "master_account",
  "executor_config": {
    "type": "order_executor",
    "connector_name": "solana-mainnet-beta",
    "trading_pair": "SOL-USDC",
    "side": 2,
    "amount": "0.02",
    "execution_strategy": "MARKET"
  }
}'
  • With #8377: the executor reaches RUNNING, sizes the order, submits through the unified /trading/swap/execute route, and fills on-chain (GET /executors/{id}POSITION_HOLD with a non-zero filled_amount_quote); verify the SOL→USDC balance change on-chain.
  • Without #8377 (development hummingbot): the executor dies at on_start with Invalid connector. solana-mainnet-beta does not exist in AllConnectorSettings — this is exactly what #8377 fixes.
  • Mint-address token: run the same config with a memecoin's mint address as the base token (a pair absent from Gateway's symbol list) — on development it crashes in get_order_size_quantum with KeyError; with #8377 it quantizes to 6 decimals and submits.

4. Bad input + regression

  • Bogus connector_name (e.g. solana-typo-net) → the deploy fails fast with HTTP 500 Unknown network … at start_network, no executor is left running, and the bad name is not registered in AllConnectorSettings.
  • CEX regression: run a normal CEX order_executor (e.g. binance paper trade) and confirm the standard BudgetChecker balance validation still behaves as before.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ko4KsGwUaHjqiRTYon31Li

… errors

GatewayClient:
- swaps go through Gateway's unified /trading/swap/{quote,execute} instead of
  /connectors/{c}/router/*, which 404'd for clmm-only connectors (meteora,
  orca) and doubled the path for typed values like "jupiter/router"
- normalize_swap_connector(): bare router connectors (jupiter, 0x, uniswap,
  pancakeswap) get /router appended, everything else /clmm; typed values
  pass through
- CLMM ops go through unified /trading/clmm/* with the schema Gateway
  actually expects (chainNetwork, walletAddress, percentageToRemove)
- add GatewayError + check_gateway_error() for the {"error","status"} dict
  _request returns on non-OK responses

Callers:
- /gateway/swap/quote no longer renders a Gateway 404 as a 200 quote with
  price "0" — Gateway errors propagate with their real status code
- _refresh_position_data no longer closes DB positions when
  positions-owned returns a Gateway error
- transaction poller treats Gateway HTTP errors as transient instead of
  recording them as on-chain FAILED
- gecko price source no longer caches an empty token map on Gateway errors
- slippage_pct=0 was dropped as falsy everywhere; use `is not None`

Adds contract tests pinning paths/payload keys and error propagation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ko4KsGwUaHjqiRTYon31Li
@rapcmia rapcmia self-assigned this Jul 16, 2026
@rapcmia rapcmia moved this to Backlog in Pull Request Board Jul 16, 2026
@fengtality fengtality moved this from Backlog to Under Review in Pull Request Board Jul 17, 2026
…n AllConnectorSettings

Gateway network connectors (e.g. 'solana-mainnet-beta') are only enumerated into
hummingbot's AllConnectorSettings by GatewayHttpClient's status monitor, which reads
/config/chains when Gateway comes online. That monitor is started by the standalone
client's TradingCore but was never started here, so Gateway networks were absent from
AllConnectorSettings until a connector for one happened to be constructed on demand.

Start the monitor in the app lifespan (and stop it on shutdown). Newly added chains
(e.g. unichain, robinhoodchain) now enumerate without first deploying a bot on them,
and the monitor picks up Gateway coming online later. Startup is unaffected when
Gateway is unreachable — the monitor pings in the background and simply stays offline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lur3b8AWCGzTQq3cG6kjxr
@rapcmia rapcmia changed the title fix(gateway): use unified /trading endpoints and stop masking Gateway errors fix / gateway use unified /trading endpoints and stop masking Gateway errors Jul 20, 2026
@rapcmia

rapcmia commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Commit e1dd9af

  • Successfully build docker image of HAPI using local .whl of hbot/8377

Start HAPI using make deploy failed due to AttributeError: 'NoneType' object has no attribute 'password'

image
2026-07-20 12:59:43,092 - hummingbot.core.gateway.gateway_http_client - ERROR - ✗ Failed to ping gateway: AttributeError: 'NoneType' object has no attribute 'password'
Traceback (most recent call last):
  File "/opt/conda/envs/hummingbot-api/lib/python3.12/site-packages/hummingbot/core/gateway/gateway_http_client.py", line 497, in ping_gateway
    response: Dict[str, Any] = await self.api_request("get", "", fail_silently=True)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/conda/envs/hummingbot-api/lib/python3.12/site-packages/hummingbot/core/gateway/gateway_http_client.py", line 433, in api_request
    client = self._http_client(self._gateway_config)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/conda/envs/hummingbot-api/lib/python3.12/site-packages/hummingbot/core/gateway/gateway_http_client.py", line 120, in _http_client
    password = Security.secrets_manager.password.get_secret_value()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'password'
  • This error occurred on fresh Docker installation before Gateway had been started
  • HAPI was expected to start normally and wait for Gateway to become available however it tried to connecto before its password settings were ready, causing the NoneType error ❌
  • This behavior does not occur during normal startup on main branch

… it until mTLS certs exist

On a fresh install the monitor started by e1dd9af pinged Gateway every 2s
before anything had populated Security.secrets_manager (it was only set
lazily on first connector creation), so each ping crashed building the mTLS
client with "AttributeError: 'NoneType' object has no attribute 'password'".

- Log master_account in during lifespan startup, before the GatewayHttpClient
  singleton is created, so Security.secrets_manager is always set (and a wrong
  CONFIG_PASSWORD now fails startup with a clear error instead of surfacing
  later as decrypt failures).
- When Gateway is secured (https) but the shared mTLS certs haven't been
  generated yet (fresh install, Gateway never started), defer the monitor
  instead of letting every ping fail loudly on the missing cert files.
  GatewayService.start() starts it right after generating the certs
  (start_monitor is a no-op when already running).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@rapcmia

rapcmia commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Commit 8758059

Start HAPI using make deploy failed due to AttributeError: 'NoneType' object has no attribute 'password' ❌

  • Reported issue on password has been fixed ✅
  • Start Gateway through hummingbot-api without restarting the API ✅
  • Confirm GET /connectors/ eventually includes solana-mainnet-beta and the other configured Gateway networks. ✅
    curl -s -u admin1:admin2 http://localhost:8000/gateway/chains |
      jq '[.chains[] | .chain as $chain | .networks[] | "\($chain)-\(.)"]'
    
    curl -s -u admin1:admin2 http://localhost:8000/connectors/ |
      jq '[.[] | select(startswith("ethereum-") or startswith("solana-"))]'
    
    Both commands returned the same 11 networks:
    [
      "ethereum-arbitrum",
      "ethereum-avalanche",
      "ethereum-base",
      "ethereum-bsc",
      "ethereum-celo",
      "ethereum-mainnet",
      "ethereum-optimism",
      "ethereum-polygon",
      "ethereum-sepolia",
      "solana-devnet",
      "solana-mainnet-beta"
    ]
    
    • The network IDs generated from GET /gateway/chains exactly matched the Gateway network IDs returned by GET /connectors
    • All 11 networks are avail;able, including solana-mainnet-beta and soalna-devnet
  • Run the two developer test files and record the stated 32 passing tests. ✅
  • Test a valid Jupiter quote, slippage_pct: 0, and a invalid connector.
    #### Valid jupiter quote
    curl -s -u admin1:admin2 -H 'Content-Type: application/json' -X POST http://localhost:8000/gateway/swap/quote -d '{
      "connector": "jupiter",
      "network": "solana-mainnet-beta",
      "trading_pair": "SOL-USDC",
      "side": "SELL",
      "amount": 0.01,
      "slippage_pct": 1.0
    }' | jq
    
    {
      "base": "SOL",
      "quote": "USDC",
      "price": "76.9555",
      "amount": "0.01",
      "amount_in": "0.01",
      "amount_out": "0.769555",
      "expected_amount": "0.769555",
      "slippage_pct": "1.0",
      "gas_estimate": null
    }
    
    #### Jupiter quote with zero slippage 
    curl -s -u admin1:admin2 -H 'Content-Type: application/json' -X POST http://localhost:8000/gateway/swap/quote -d '{
      "connector": "jupiter",
      "network": "solana-mainnet-beta",
      "trading_pair": "SOL-USDC",
      "side": "SELL",
      "amount": 0.01,
      "slippage_pct": 0
    }' | jq
    
    {
      "base": "SOL",
      "quote": "USDC",
      "price": "76.9525",
      "amount": "0.01",
      "amount_in": "0.01",
      "amount_out": "0.769525",
      "expected_amount": "0.769525",
      "slippage_pct": "0",
      "gas_estimate": null
    }
    
    #### Invalid conenctor error body
    curl -s -u admin1:admin2 -H 'Content-Type: application/json' -X POST http://localhost:8000/gateway/swap/quote -d '{
      "connector": "bogus",
      "network": "solana-mainnet-beta",
      "trading_pair": "SOL-USDC",
      "side": "SELL",
      "amount": 0.01,
      "slippage_pct": 1.0
    }' | jq
    
    {
      "detail": "Gateway error getting swap quote: Failed to get swap quote: Unsupported chain: bogus. Supported chains: ethereum, solana"
    }
    
    • The Jupiter requests confirmed unified swap quoting works with or without slippage value ok
    • Invalid connector response kept Gateway real error and non-200 status instead of successful zero-price quote

Test in progress:

  • Test a read-only CLMM request and error propagation for an unknown position.
  • Test with hbot/8377, complete the Gateway OrderExecutor, mint-address token, invalid-network, and CEX regression checks

@fengtality

fengtality commented Jul 20, 2026 via email

Copy link
Copy Markdown
Contributor Author

@rapcmia

rapcmia commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

PR update:

Try testing the case where the Gateway container is already running when
the user starts the Hummingbot API, as well as when it's not running and
the user starts it with the Hummingbot API.
GET /connectors/ should work in both cases

(base) eddga :: ~/hummingbot » docker ps | grep gateway                                                                                         
bf37f595173a   hummingbot/gateway:dev             "docker-entrypoint.s…"   12 minutes ago   Up 12 minutes           127.0.0.1:15888->15888/tcp                                                                                   gateway
(base) eddga :: ~/hummingbot »   curl -sS -u admin1:admin2 http://localhost:8000/connectors/ | jq 'map(select(test("^(ethereum|solana)"; "i")))'
[
  "ethereum-arbitrum",
  "ethereum-avalanche",
  "ethereum-base",
  "ethereum-bsc",
  "ethereum-celo",
  "ethereum-mainnet",
  "ethereum-optimism",
  "ethereum-polygon",
  "ethereum-sepolia",
  "solana-devnet",
  "solana-mainnet-beta"
]
  • Start HAPI without gateway ✅
    • No gateway connectors on the list
  • Start HAPI with active gateway ✅
    • Gateway networks are added after HAPI detects gateway
    • They ramain in /connectors even after gateway stop
    • /gateway/{status, connectors} correctly reflect live availability
    • Restarting HAPI while gateway is offline clears the dynamic entries
  • Start HAPI without gateway then start it, still ok ✅

Test a read-only CLMM request and error propagation for an unknown position. ✅

#### Read-only Meteora CLMM pool info:
curl -sS -u admin1:admin2 'http://localhost:8000/gateway/clmm/pool-info?connector=meteora&network=solana-mainnet-beta&pool_address=2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3' | jq '{address, base_token_address, quote_token_address, bin_step, fee_pct, price, active_bin_id, bins_count: (.bins | length)}'
{
  "address": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3",
  "base_token_address": "So11111111111111111111111111111111111111112",
  "quote_token_address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "bin_step": 100,
  "fee_pct": "0.04",
  "price": "78.29396937632126",
  "active_bin_id": -256,
  "bins_count": 141
}

#### Unknown CLMM position removal request with HTTP status capture
curl -sS -u admin1:admin2 -H 'Content-Type: application/json' -X POST http://localhost:8000/gateway/clmm/add -d '{
  "connector": "meteora",
  "network": "solana-mainnet-beta",
  "position_address": "11111111111111111111111111111111",
  "base_token_amount": 0.000001,
  "quote_token_amount": 0.000001,
  "slippage_pct": 1
}' -w '\n{"http_status":%{http_code}}\n' | jq -s '{response: .[0], http_status: .[1].http_status}'

{
  "response": {
    "detail": "Gateway error adding liquidity: Position not found: 11111111111111111111111111111111. Please provide a valid position address"
  },
  "http_status": 404
}

curl -sS -u admin1:admin2 -H 'Content-Type: application/json' -X POST http://localhost:8000/gateway/clmm/remove -d '{
  "connector": "meteora",
  "network": "solana-mainnet-beta",
  "position_address": "11111111111111111111111111111111",
  "percentage": 1
}' -w '\n{"http_status":%{http_code}}\n' | jq -s '{response: .[0], http_status: .[1].http_status}'
{
  "response": {
    "detail": "Gateway error removing liquidity: Position not found: 11111111111111111111111111111111. Please provide a valid position address"
  },
  "http_status": 404
}
  • Test with Meteora CLMM pool data
  • Removing liquidity from an intentional unknown position returned GW specific position-not-found message with HTTP 404
  • No txhash were returned, so no liquidity-removal txn was submitted

Test with hbot/8377, complete the Gateway OrderExecutor, mint-address token, invalid-network, and CEX regression checks ✅

#### Add OFFICIAL TRUMP by mint address:
curl -sS -u admin1:admin2 -X POST http://localhost:8000/gateway/networks/solana-mainnet-beta/tokens/save/6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN | jq
{
  "success": true,
  "message": "Token TRUMP has been added to the token list for solana/mainnet-beta",
  "token": {
    "symbol": "TRUMP",
    "address": "6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN",
    "decimals": 6,
    "name": "OFFICIAL TRUMP",
    "network_id": "solana-mainnet-beta"
  }
}

#### Quote the mint-address swap:
curl -sS -u admin1:admin2 -H 'Content-Type: application/json' -X POST http://localhost:8000/gateway/swap/quote -d '{
  "connector": "jupiter",
  "network": "solana-mainnet-beta",
  "trading_pair": "USDC-6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN",
  "side": "SELL",
  "amount": 0.25,
  "slippage_pct": 1.0
}' | jq
{
  "base": "USDC",
  "quote": "6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN",
  "price": "0.62534",
  "amount": "0.25",
  "amount_in": "0.25",
  "amount_out": "0.156335",
  "expected_amount": "0.156335",
  "slippage_pct": "1.0",
  "gas_estimate": null
}

#### Execute the mint-address swap:
curl -sS -u admin1:admin2 -H 'Content-Type: application/json' -X POST http://localhost:8000/gateway/swap/execute -d '{
  "connector": "jupiter",
  "network": "solana-mainnet-beta",
  "trading_pair": "USDC-6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN",
  "side": "SELL",
  "amount": 0.25,
  "slippage_pct": 1.0
}' | jq
{
  "transaction_hash": "3buaqrX1E1ADpFQyyv342hD2Kw6ESWECDtLDbLLMYkPSTdboTbgnR2nAe8nCurGaEvfXVD7nigxGX1jyrgR2S3M8",
  "trading_pair": "USDC-6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN",
  "side": "SELL",
  "amount": "0.25",
  "status": "submitted"
}

#### Confirmed HAPI swap result
curl -sS -u admin1:admin2 http://localhost:8000/gateway/swaps/3buaqrX1E1ADpFQyyv342hD2Kw6ESWECDtLDbLLMYkPSTdboTbgnR2nAe8nCurGaEvfXVD7nigxGX1jyrgR2S3M8/status | jq
{
  "transaction_hash": "3buaqrX1E1ADpFQyyv342hD2Kw6ESWECDtLDbLLMYkPSTdboTbgnR2nAe8nCurGaEvfXVD7nigxGX1jyrgR2S3M8",
  "network": "solana-mainnet-beta",
  "connector": "jupiter",
  "wallet_address": "AbCpsXy2HAC5yWe3YwfysYk4x4FSd13WduKkCooREZK2",
  "trading_pair": "USDC-6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN",
  "base_token": "USDC",
  "quote_token": "6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN",
  "side": "SELL",
  "input_amount": 0.25,
  "output_amount": 0.156298,
  "price": 0.625192,
  "slippage_pct": 1.0,
  "status": "CONFIRMED",
  "error_message": null
}

#### Wallet state after the swap:
curl -sS -u admin1:admin2 -H 'Content-Type: application/json' -X POST http://localhost:8000/portfolio/state -d '{
  "account_names": ["master_account"],
  "connector_names": ["solana-mainnet-beta"],
  "skip_gateway": false,
  "refresh": true
}' | jq
{
  "master_account": {
    "solana-mainnet-beta": [
      {
        "token": "SOL",
        "units": 0.35160510300000003,
        "available_units": 0.35160510300000003
      },
      {
        "token": "USDC",
        "units": 1.315996,
        "available_units": 1.315996
      }
    ]
  }
}
  • Test using TRUMP-USDC then used the mind directly in the swap trading pair
  • Sold through jupiter and received TRUMP, reported the swap as CONFIRMED and solana txn as finalized with no error
  • Created a github issue on /portfolio/state route where it does not add display the tokens i added on the list e.g TRUMP Portfolio API - Gateway wallet tokens are missing from portfolio state #195

Invalid gateway network fails without creating or registering an executor ✅


#### Submit the OrderExecutor with an invalid Gateway network and capture the HTTP status:
curl -sS -u admin1:admin2 -H 'Content-Type: application/json' -X POST http://localhost:8000/executors/ -d '{
  "account_name": "master_account",
  "executor_config": {
    "type": "order_executor",
    "connector_name": "solana-typo-net",
    "trading_pair": "SOL-USDC",
    "side": 2,
    "amount": "0.02",
    "execution_strategy": "MARKET"
  }
}' -w '\n{"http_status":%{http_code}}\n' | jq -s '{response: .[0], http_status: .[1].http_status}'

{
  "response": {
    "detail": "Error creating executor: Gateway error: body/network must be equal to one of the allowed values (Validation Error)"
  },
  "http_status": 500
}

#### Search specifically for running executors associated with the invalid connector:
curl -sS -u admin1:admin2 -H 'Content-Type: application/json' -X POST http://localhost:8000/executors/search -d '{
  "account_names": ["master_account"],
  "connector_names": ["solana-typo-net"],
  "executor_types": ["order_executor"],
  "status": "RUNNING",
  "limit": 100
}' | jq

{
  "data": [],
  "pagination": {
    "limit": 100,
    "has_more": false,
    "next_cursor": null,
    "total_count": 0
  }
}
  • Submitted a OrderExecutor with invalid connector_name failed immediately with gateway error
  • The request failed before an executor was stored or started, and no funds could move on the invalid network

Regression tests on CEX using OrderExecutor ✅

  • Both buy and sell market orders TERMINATED with POSITION_HOLD, non-zero exchange order Ids and matched wallet changes
  • Test an oversized 1 BTC and it terminated immediately with INSUFFICIENT_BALANCE, no exchange order ID nor zero fill and fees. No order found on exchange as well

@rapcmia rapcmia left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • Gateway startup, restart, and connector-network lifecycle checks.
  • All 11 configured Ethereum and Solana networks appeared in /connectors/.
  • Developer tests: 32 passed with 8 warnings.
  • Jupiter quote, zero-slippage, and invalid-connector error propagation.
  • Read-only CLMM request and unknown-position add/remove liquidity errors.
  • Solana Gateway OrderExecutor market sell with non-zero fill and wallet update.
  • Jupiter swap using a mint-address token.
  • Invalid-network rejection without creating or registering an executor.
  • Gate.io CEX regression:
    • Successful BTC-USDT market buy and sell.
    • Oversized order terminated with INSUFFICIENT_BALANCE.
    • No order ID, fills, fees, balance change, active order, or running executor.
    • Manually confirmed no order appeared in Gate.io exchange history.

A Gateway network such as 'solana-mainnet-beta' can exist twice in the
account-state pipeline: as a unified Gateway trading connector and as a
Gateway wallet fetched by _update_gateway_balances. Both wrote the same
accounts_state[account]['solana-mainnet-beta'] key, and since connector
results are applied after the gather, the connector view always won.

That view is much narrower: gateway_base.update_balances() only queries
Gateway for the tokens of the connector's trading pairs plus the native
currency, so wallet tokens the connector doesn't trade disappear from
portfolio state, and mint-address trading pairs report mint addresses
instead of symbols.

Skip Gateway connectors in the per-connector balance pass so the full
wallet snapshot is the single source of truth for those keys, and mirror
it onto non-master accounts holding the same connector (they trade the
same Gateway default wallet) so their state doesn't go stale.

Verified against a live Gateway: portfolio state now returns all seven
wallet tokens with symbols, matching POST /chains/solana/balances; on the
previous code the same setup returned four.

Fixes #195

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@fengtality
fengtality merged commit 66eb91d into main Jul 21, 2026
@rapcmia rapcmia moved this from Under Review to Condor in Pull Request Board Jul 22, 2026
@rapcmia rapcmia moved this from Condor to Hummingbot-API in Pull Request Board Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Hummingbot-API

Development

Successfully merging this pull request may close these issues.

2 participants