Skip to content

fix(api): one parameter name per path on /tokens/{} and /pools/{} - #710

Open
ipezygj wants to merge 2 commits into
hummingbot:developmentfrom
ipezygj:fix/one-parameter-name-per-path
Open

ipezygj wants to merge 2 commits into
hummingbot:developmentfrom
ipezygj:fix/one-parameter-name-per-path

Conversation

@ipezygj

@ipezygj ipezygj commented Sep 21, 2026 •

Copy link
Copy Markdown

Before submitting this PR, please make sure:

  • Your code builds clean without any errors or warnings
  • You are using approved title ("feat/", "fix/", "docs/", "refactor/")

A description of the changes proposed in the pull request:

Fixes #689, taking option 1 from the issue: one parameter name per path, with the parameter genuinely meaning the same thing under both verbs.

shape before after
/tokens/{} GET {symbolOrAddress} · DELETE {address} GET and DELETE {symbolOrAddress}
/pools/{} GET {tradingPair} · DELETE {address} GET and DELETE {tradingPairOrAddress}
  • DELETE /tokens/{symbolOrAddress} resolves the id against the token list and removes the token it names; an unknown symbol or address is a 404 before anything is touched. One deliberate difference from GET: the address is matched before the symbol. GET tries the symbol first, the right order for a read, but a delete must never remove a token whose symbol happens to equal the address that was named (symbols are only required to be non-empty). The message names both symbol and address of what was removed.
  • Both pool routes read a pair as exactly BASE-QUOTE; a three-segment id is not the pair of its first two and is refused rather than truncated.
  • GET /pools/{tradingPairOrAddress} tries the id as a pool address first (getPoolByAddress, no type needed) and otherwise as a trading pair with type (and connector to narrow it), exactly as before. type becomes optional on GetPoolRequestSchema and is required by the handler only when the path names a pair.
  • DELETE /pools/{tradingPairOrAddress} takes an address as today, or a pair: a pair can name several pools (fee tiers, connectors), and a delete must name one, so it removes the pool only when exactly one matches and otherwise answers 400 listing the candidates by connector and address. Nothing is ever deleted at random.

No path changes: a client that sends an address today sends the same request and gets the same answer. operation-ids.ts and the committed openapi.json are updated (pnpm generate:openapi), so the test/spec checks that pin the route table pass against the new names.

Tests performed by the developer:

  • test/tokens/tokens.routes.test.ts: a token removed by address, by symbol, by address when another token's symbol equals that address (the named one goes, not the impostor), and a 404 for an unknown id with removeToken never called.
  • test/pools/pools.routes.test.ts: GET by address without type; GET by pair without type is a 400 naming the missing field; DELETE by pair with one match removes that address; with two matches answers 400 naming both and removes nothing; by pair without type is a 400; SOL-USDC-EXTRA is a 404 with nothing listed or removed; the existing address cases unchanged.
  • test/spec, test/pools, test/tokens: 306 passed. pnpm typecheck, eslint and prettier clean on the changed files.

Tips for QA testing:

DELETE /tokens/USDC?chainNetwork=ethereum-mainnet now removes USDC (was a 404: "Token with address USDC not found"). GET /pools/<address>?chainNetwork=solana-mainnet-beta returns that pool without type. DELETE /pools/SOL-USDC?chainNetwork=solana-mainnet-beta&type=clmm removes the one SOL-USDC CLMM pool, or lists the candidates when there are several. The generated spec shows one parameter per path under /tokens/{symbolOrAddress} and /pools/{tradingPairOrAddress}.

GET /tokens/{symbolOrAddress} sat beside DELETE /tokens/{address}, and
GET /pools/{tradingPair} beside DELETE /pools/{address}: the same path
shape, with the id meaning something else per verb. A consumer that reads
the route table structurally - a generated client, a drift check - saw
one resource where there were two.

Both pairs now share a name and a meaning. DELETE /tokens/{symbolOrAddress}
resolves a symbol the way GET does and removes the token it names.
/pools/{tradingPairOrAddress}: GET and DELETE take a pool address, or a
trading pair with type (and connector to narrow it); a DELETE by pair
removes the pool only when exactly one matches and otherwise names the
candidates, so a pair that spans fee tiers or connectors never deletes
one at random. type is therefore optional on the query and required only
when the path names a pair. No path changes; a client sending an address
today sends the same request.

openapi.json regenerated.

Fixes hummingbot#689.
@greptile-apps

greptile-apps Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

The PR appears safe to merge; the latest changes fully address both previously reported destructive-resolution hazards without introducing an actionable regression.

Summary

This revision fixes both previously reviewed identifier-collision hazards while retaining the unified token and pool path parameters.

  • Token deletion now resolves addresses before symbols, preventing a colliding symbol from redirecting a destructive request.
  • Pool routes require an exact BASE-QUOTE shape after address lookup fails, preventing extra segments from being silently discarded.
  • Regression tests cover address precedence and rejection of three-segment pool identifiers.
  • The generated OpenAPI document and operation-ID mappings reflect the unified route parameters.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Token or pool identifier] --> B{Direct address match?}
    B -->|Yes| C[Operate on matched address]
    B -->|No| D{Token route?}
    D -->|Yes| E[Resolve symbol case-insensitively]
    D -->|No| F{Exactly BASE-QUOTE and valid type?}
    F -->|No| G[Reject request]
    F -->|Yes| H[Find matching pools]
    H --> I{Exactly one match?}
    I -->|Yes| C
    I -->|No| G
Loading

Reviews (2) · Last reviewed commit: "fix(api): a delete by address wins over ..."

Comment thread src/tokens/routes/removeToken.ts Outdated
Comment thread src/pools/routes/removePool.ts Outdated
…r is exactly two segments

GET resolves a symbol before an address, the right order for a read; a
delete must never remove a token whose symbol happens to equal the
address that was named, so DELETE /tokens/{symbolOrAddress} matches the
address first. And a three-segment id is not the pair of its first two:
both pool routes require exactly BASE-QUOTE.
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.

1 participant