Skip to main content

Hydrex Plugin

[!IMPORTANT] Run Base MCP onboarding first (see SKILL.md). Obtain the user’s wallet address via get_wallets — it is required as from or recipient in every prepare call. The Hydrex prepare server must be running locally before any write operations.

Overview

Hydrex is an Omni-Liquidity MetaDEX on Base — concentrated-liquidity swaps aggregated across 0x, OpenOcean, OKX, and KyberSwap, plus liquidity positions that earn fees and rewards automatically. Adding liquidity creates an active earning position immediately; there is no separate staking step. The plugin calls a local prepare server (https://hydrex-agent.com) to fetch unsigned calldata, then submits via send_calls on Base mainnet (chainId: 8453).

Surface Routing

The prepare server (https://hydrex-agent.com) is not on the Base MCP web_request allowlist. On chat-only surfaces, construct the full GET URL with all query parameters and ask the user to open it in a browser, paste the JSON response into chat, then continue with send_calls.

Endpoints

Server URL: https://hydrex-agent.com

GET /health

Response: { "ok": true, "service": "hydrex-base-skill-server", "chainId": 8453 }

GET /state/quote

Response:
Always show amountOut (human-readable) and priceImpact to the user before executing. Warn and require confirmation if priceImpact > 5%.

GET /state/portfolio

Returns token balances and LP positions for the wallet.

GET /state/positions

Returns all open concentrated liquidity positions owned by the wallet (read from NonfungiblePositionManager on-chain). Response shape:
Use positionId with /prepare/remove-liquidity.

GET /state/trade-history

Returns past swaps executed through Hydrex for the wallet.

GET /state/pools

Discovers Hydrex pools — including each pool’s contract address, token addresses, and decimals — from the Hydrex stats API. This is how the agent resolves a pool address (and token0/token1/decimals0/decimals1) for /prepare/add-liquidity and /prepare/remove-liquidity when the user only gives a token pair. Pass tokenA + tokenB to find pools for a specific pair regardless of token order. With no token filters it returns every pool. Results are sorted by TVL (USD) descending, so pools[0] is the deepest pool for the pair. Response:
Each entry gives the pool address plus token0/token1 addresses and decimals — exactly the inputs /prepare/add-liquidity needs (use them directly, preserving the returned token0/token1 order). Handling:
  • count = 0 — no pool exists for that pair; tell the user and do not call a prepare endpoint.
  • count > 1 — multiple pools/fee tiers; show the options (tvlUsd, fee, liquidityType) and let the user choose before proceeding.
  • count = 1 — use it; confirm with the user before any write.
Never guess or fabricate a pool address — discover it here, or ask the user (addresses are also listed on the Hydrex app at https://hydrex.fi).

GET /prepare/swap

Example:
Response:
The transactions[] array length is not fixed. For an ERC-20 tokenIn, an approve-tokenIn step is prepended only when the wallet’s current allowance is too low — if allowance is already sufficient, just the swap step is returned. Native ETH swaps never include an approve step. Always pass every returned transaction to send_calls in order, rather than assuming a single call.

GET /prepare/add-liquidity

The range is set in exactly one of these mutually exclusive ways — rangePreset, a custom priceLower+priceUpper, or fullRange. Sending more than one returns 400 (“Choose only one range option…”); sending only one of priceLower/priceUpper returns 400 (“A custom range requires both…”). If you send none, the server uses the common preset (±12.5%). Response — three transactions, always in this order:

Price range selection

Choose one of three mutually exclusive ways to set the range (the server does the percentage→price math on-chain, so the agent only passes the choice): If the user gives no preference, the server applies the common preset (±12.5%). Always tell the user which range was used, e.g. “I’m using the common ±12.5% range around the current price — say the word for a tighter (narrow/tight), wider (wide), full, or custom range.”

GET /prepare/remove-liquidity

Response:
All prepare endpoints return { "ok": false, "error": "..." } on failure — surface the error field to the user and do not call send_calls.

Orchestration

Swap

Add liquidity (enter a position)

Remove liquidity (exit a position)

Submission

Target tool: send_calls Map every transactions[] array from a prepare endpoint into send_calls:
Pass all transactions in a single calls array — Base MCP executes them atomically in one user approval. After send_calls returns, immediately call get_request_status(requestId) and poll until the status is success or failed. Do not ask the user to type or paste anything during polling. See approval-mode.md.

Example Prompts

“Swap 5 USDC for ETH on Hydrex”
  1. get_wallets → wallet address
  2. GET /state/quote?tokenIn=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&tokenOut=0x4200000000000000000000000000000000000006&amount=5000000&recipient=<address> → show amountOut, priceImpact
  3. GET /prepare/swap?tokenIn=0x833589...&tokenOut=0x420000...&amount=5&decimals=6&recipient=<address>&slippage=50
  4. send_calls(chain="base", calls=[swap tx])
  5. Poll get_request_status → report outcome
“Show my Hydrex liquidity positions”
  1. get_wallets → wallet address
  2. GET /state/positions?address=<address> → display each positionId, token pair, tick range, and liquidity
“Add liquidity to the USDC/ETH pool on Hydrex — 100 USDC and 0.04 ETH”
  1. get_wallets → wallet address
  2. GET /state/positions?address=<address> → existing position context (count may be 0 — fine for a first position)
  3. GET /state/pools?tokenA=USDC&tokenB=WETH → pick the pool (if count > 1, let the user choose); read its pool/token0/token1/decimals. Range defaults to the common preset (±12.5%) unless the user picks another; inform the user of the range used
  4. GET /prepare/add-liquidity?from=<address>&pool=<pool>&token0=<USDC>&token1=<WETH>&decimals0=6&decimals1=18&amount0=100&amount1=0.04
  5. Show returned position (tickLower, tickUpper, amounts) to user
  6. send_calls(chain="base", calls=[approve-token0, approve-token1, mint])
  7. Poll get_request_status → report outcome
“Remove 50% of liquidity from Hydrex position #12345” (chat-only surface fallback)
  1. get_wallets → wallet address
  2. web_request cannot reach https://hydrex-agent.com → construct the full URL and ask the user to open it in a browser and paste the JSON response into chat
  3. On receiving JSON, send_calls(chain="base", calls from transactions[])
  4. Poll get_request_status → report outcome

Risks & Warnings

  • Slippage — swap and liquidity operations fill at market price; actual output can differ from the quote. Default tolerance is 50 bps (0.5%). Always check priceImpact before executing; if priceImpact > 5%, warn the user and wait for explicit confirmation. Never auto-raise slippage.
  • Irreversible — onchain transactions cannot be undone once approved. Always show the user the full operation details (amounts, price range for LP positions, positionId for removals) and confirm before calling send_calls.

Notes

Well-known token addresses (Base mainnet)

For other tokens, look up the address (and decimals) via GET /state/pools (returns token0/token1 with address, symbol, and decimals), or ask the user to supply the contract address.

Error handling

Liquidity notes

  • Adding liquidity creates a concentrated liquidity position that earns fees and rewards automatically — no separate staking step is required.
  • Removing liquidity fully exits the position and returns both tokens to the wallet.
  • The positionId is the NFT tokenId from the NonfungiblePositionManager; always fetch current positions via /state/positions before a remove.