Avantis Plugin
[!IMPORTANT] Complete the short Base MCP onboarding flow defined inSKILL.mdbefore calling any Avantis endpoint. The user’s wallet address — used astraderin every tx-builder call — is fetched lazily when needed.
Overview
Avantis is a perpetual futures DEX on Base mainnet (chainId 8453). The plugin returns unsigned call data; signing and broadcasting are the wallet’s job (Base MCP send_calls). Collateral is USDC only; ETH is used only for gas and the Avantis execution-fee value. View-only reads work on every surface; transaction-building needs a CLI/HTTP harness, with an Avantis web UI fallback on chat-only surfaces. Aligned with the canonical Avantis-Labs/avantis-trading-skill spec.
Surface Routing
Routing order for any Avantis HTTP call:
- Harness HTTP tool (
curl,fetch, shell) — works for every host, any method, no allowlist. - Base MCP
web_request— chat-only surfaces, view-only hosts only. - Avantis web UI — chat-only surfaces, tx-builder operations. See Chat-only fallback.
send_calls approval links is safe; the user approves any real transaction.
No API key or Authorization header is required for the documented public endpoints. The general HTTP routing rules also live in ../references/custom-plugins.md.
[!IMPORTANT] CORS caveat forweb_request. Most Avantis hosts returnAccess-Control-Allow-Origin: *, but two paths are not in the open-CORS prefix list:Base MCP
https://api.avantisfi.com/v2/history/referral/*https://api.avantisfi.com/v2/market-order-initiated/*web_requestis a server-side fetch and is not affected by browser CORS, so these still work fromweb_request. Only flag this if you ever proxy these requests from a browser context.
Chat-only fallback: Avantis UI
When the user wants a tx-builder action (open, close, cancel, margin update, TP/SL change, USDC approval, delegate set/remove) and there is no shell, terminal, or direct HTTP tool in the current surface (typical for ChatGPT, Claude.ai):-
Use
web_requestagainstdata.avantisfi.com,core.avantisfi.com, orapi.avantisfi.comto answer the read side of the question (pair info, the user’s open positions, recent PnL). - Tell the user plainly that signing and submitting Avantis trades from this surface requires the Avantis web UI (or a CLI harness like Claude Code, Codex, or Cursor terminal).
-
Build a deep link to the relevant market and surface it as a clickable link. URL pattern:
<SYMBOL>is the pair’sfromfrompairInfos["<pairIndex>"](e.g.BTC,ETH,SNDK). Examples:https://www.avantisfi.com/trade?asset=ETH-USDhttps://www.avantisfi.com/trade?asset=BTC-USDhttps://www.avantisfi.com/trade?asset=SNDK-USD
- If the user already supplied concrete trade parameters (side, leverage, collateral, TP, SL), summarize them in your message so they can reproduce the intent inside the UI. Do not claim the position was opened or modified — the UI flow is user-driven.
web_request on the same surfaces.
Endpoints
API Services
Source of truth for tx-builder shape:
Step 1 — Pair, Leverage, Liquidity (data API)
pairInfos["<pairIndex>"] to inspect a pair. Important fields:
All numeric fields here are already human-decimal — no
1e6 / 1e10 math.
Market-open logic (for market orders):
- Open if
feed.attributes.is_open === true, ornow > feed.attributes.next_openandnow < feed.attributes.next_close. - Closed if
is_open === falseandnext_open > 0andnow < next_open.
positionSize must be <= available, otherwise tx-builder will reject with BAD_REQUEST (insufficient liquidity).
Minimum-position check (BELOW_MIN_POS):
~5 min TTL). If you call it directly from a hot path, cache locally too.
Step 2 — Positions and Limit Orders (core backend)
positions[] scaling:
limitOrders[] adds:
Unknown or malformed traders return
{ positions: [], limitOrders: [] }, not an error. Treat empty as “no open state”, not “lookup failed”.
Other core endpoints (rarely needed by agents):
GET /open-interests— per-pairlongOI / shortOI / pendingLongOI / pendingShortOI(USDC, human decimals).GET /v2/open-interests— same plus per-market-makermmDatabreakdown.GET /user-data/config?wallet=0x...— one-click-trading feature flags. Not a trading-permission gate.GET /health— plain textOK.
HTTP 429 under load).
Step 3 — Approve USDC
Exact approval:spender defaults to TradingStorage. to is USDC; value is 0x0. Approval must be confirmed on chain before trade calls that require allowance can succeed, unless approval and action are submitted as a valid batch and the wallet/account contract supports the batch.
Step 4 — Open A Trade
Order types (and on-chain enum)
Note the counterintuitive ordering:
stop_limit=1 and limit=2, not the other way round. Important when decoding logs.
value on the returned tx is the execution fee in wei.
ZFP example (small notional):
Pair separators
pair accepts /, -, or _. BTC/USD, btc-usd, eth_usd all resolve. Use &pairIndex= directly if you already have the integer.
Pre-Trade Validation
tx-builder enforces four checks on /trade/open before encoding. Each failure is 400 BAD_REQUEST with a human-readable message:
On success,
meta.validation carries the computed envelope:
&skipValidation=true unless the user explicitly asks.
BELOW_MIN_POS recovery: compute minCollateral = ceil(pair.pairMinLevPosUSDC / leverage) and minLeverage = ceil(pair.pairMinLevPosUSDC / collateralUsdc), then present both options to the user (within the pair’s leverage envelope). Do not silently adjust parameters.
Step 5 — Close, Cancel, Margin, TP/SL
Always readcore /user-data first and use real indices from the returned arrays.
Close
value is the execution fee in wei.
Cancel resting limit / stop-limit
value is 0x0.
Deposit / withdraw margin
value is 0x1. When priceUpdateData is omitted, tx-builder fetches it from feed-v3.avantisfi.com and picks priceSourcing based on the pair’s Lazer status (lazerFeed.state === 'stable' → 1; otherwise 0). To run fully offline supply both priceUpdateData and priceSourcing.
Set / update TP and SL
value is 0x1. Same Pyth auto-fetch behavior as /margin/update.
To modify a resting limit order’s parameters, cancel it via /trade/cancel and create a new /trade/open with orderType=limit (or stop_limit).
Delegated Trading
from is the trader (only the trader can grant or revoke). value is 0x0. After a delegate is set, any trade-side endpoint accepts &delegate=<delegateAddress>; the response from becomes the delegate, the delegate signs, and the position still belongs to trader.
Only one delegate per trader; /delegate/set replaces any prior delegate.
History And PnL (history API)
Allapi.avantisfi.com endpoints return HTTP 200 even on logical failure and use the legacy envelope:
success before reading data. userAddress must be 0x-prefixed; the service short-circuits otherwise.
Endpoint reference
Correct page index — examples:
/history response
event.args.tis the on-chainTradestruct at open time.event.args.positionSizeUSDCis the collateral closed in this event, not the position notional._grossPnlis per-close gross PnL in USDC (negative = loss).
/all response adds
open flips from true to false after the trade closes.
/profit-loss response
_mapped_netPnlwhenevent.args.isPnl === true(ZFP)._mapped_grossPnlotherwise (fixed-fee).
pairIndex is null.
/referral/stats response
1e6).
Rate limit
History API: ~10 req/s per IP. Batch and cache when possible.Current tx-builder Endpoint Inventory
Orchestration
core /user-data first and use the real positions[i].index (positions) or limitOrders[i].index (resting orders) as tradeIndex. tx-builder will encode call data for an index that does not exist, and the call will then revert on chain.
Portfolio Inspection Recipe
To answer “show me my Avantis activity” combine three sources:
Sketch:
/user-datareturns raw stringified ints (USDC/1e6, prices/leverage/1e10)./v2/history/portfolio/allmixes — most numeric fields are already human decimals./v2/history/portfolio/profit-lossreturns human decimals rounded to two places.
profit-loss for /v2/history/portfolio/top/<addr>/5 (top 5 by net PnL).
Cross-Recipe Pattern: Agent Loop
Submission
Target tool:send_calls (chain "base"). tx-builder endpoints return unsigned calldata; forward { to, value, data } into send_calls, walk the approval flow (see ../references/approval-mode.md), and for market opens/closes confirm settlement by polling the history API (below).
tx-builder Response Envelope
All calldata-producing tx-builder endpoints return:
Errors:
BAD_REQUEST, VALIDATION_ERROR (with details.fieldErrors), UPSTREAM_ERROR, NOT_FOUND, INTERNAL_ERROR.
send_calls payload:
Batching With send_calls
- Approval + open trade.
- Approval + margin deposit.
- Cancel resting order + create replacement limit order.
- Multiple independent generated calls, all on Base, that are logically safe together.
Settlement Polling (history API)
Market opens and closes settle after the submitted transaction emits aMarketOrderInitiated event. Only poll when you have a real tx hash from a submitted transaction.
status is one of:
Unknown hashes return HTTP 200 with
{ "success": false, "errorMessage": "Market order not found ..." }. Treat as still-pending or invalid hash — do not interpret as canceled.
Polling pattern (exponential backoff, ~60 s cap):
core /user-data and emit LimitExecuted events on chain.
Example Prompts
Open a 10x long on BTC/USD with 100 USDCget_wallets→trader.GET data /v2/trading→ confirmisPairListed, market open, leverage envelope, and liquidity for BTC/USD.GET core /user-data?trader=...to check existing allowance/positions; if allowance missing,GET tx-builder /token/approve?trader=....GET tx-builder /trade/open?trader=...&pair=BTC/USD&side=long&orderType=market&collateralUsdc=100&leverage=10&slippagePercent=1→ reviewmeta.validation.send_calls(chain="base", calls=[approve?, open]); approve; poll/v2/market-order-initiated/status/<txHash>; re-readcore /user-data. (Chat-only surface: link the Avantis UI instead — see Chat-only fallback.)
get_wallets→trader.GET core /user-data?trader=...→ open positions + resting limit orders (apply/1e6and/1e10scaling).GET api /v2/history/portfolio/all/<addr>/1/20andGET .../profit-loss/<addr>/grouped→ summarize (see Portfolio Inspection Recipe).
get_wallets→trader.GET core /user-data?trader=...→ find the BTC position’spairIndexandindex.GET tx-builder /trade/close?trader=...&pairIndex=...&tradeIndex=...&collateralUsdc=<full collateral>.send_calls; approve; poll settlement; re-readcore /user-data.
get_wallets→trader.GET core /user-data?trader=...→ ETH position’spairIndexandindex.GET tx-builder /tpsl/update?trader=...&pairIndex=...&tradeIndex=...&takeProfit=80000&stopLoss=<keep or 0>.send_calls; approve.
Risks & Warnings
Perpetual futures are leveraged and can be fully liquidated. Build calldata freely, but never sign or submit without explicit user approval — opened/closed trades are irreversible onchain actions.- Liquidation. A position liquidates once loss exceeds ~85% of collateral (see Key Thresholds). Always read
core /user-dataand surfaceliquidationPricebefore and after any change. Margin withdrawals must keep the position above ~20% effective collateral. - Slippage.
slippagePercentdefaults to1. Warn the user before submitting elevated values; the protocol max slippage is 80% (_MAX_SLIPPAGE). Don’t silently raise it. - Leverage. Respect the per-pair envelope (
leverages.*); the server sanity cap (<= 1000) is far looser than the per-pair max inmeta.validation.maxLeverage. - Irreversible. Market opens/closes settle onchain and cannot be undone. Confirm side, pair, leverage, collateral, TP/SL with the user before submitting.
- Never silently retry a
BAD_REQUESTwith adjusted parameters — present options and let the user choose.
Notes
Base-Only Rules
- All tx-builder call data targets Base mainnet (
chainId8453). There is no chain selector. - Collateral is USDC only. ETH is used only for gas and the Avantis execution-fee
value. - Canonical Base USDC:
0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913. - Default USDC spender is Avantis
TradingStorage:0x8a311D7048c35985aa31C131B9A13e03a5f7422d.
Units And Scaling
Do not pass
1e6 USDC or 1e10 price units into tx-builder query parameters — they take human decimals.
Error Handling
tx-builder error envelope:
History endpoints: HTTP 200 with
success:false is the normal failure mode. For a wallet with no portfolio, some endpoints return success:false with Unable to get the portfolio. while others return success:true with empty data. Treat as empty/unknown unless the user expected existing history.
Recommended handling:
- Surface validation messages verbatim — they describe the exact constraint that failed.
- For
/trade/open, inspectmeta.validationon success and show the user position size, min position, leverage envelope, and available liquidity when useful. - For management actions, do not rely on tx-builder to prove the position/order exists. Verify via
core /user-data. - Never silently retry a
BAD_REQUESTwith adjusted parameters; show options and ask the user.
Sanity Caps (tx-builder server-side)
These are looser than per-pair envelopes — the per-pair check still applies.
EIP-55 address handling:
trader, delegate, spender accept both checksummed and all-lowercase; the service normalizes to checksum in the response.
Scaling Quick Reference (on-chain side)
These apply when reading raw
core /user-data strings or decoding on-chain logs. tx-builder inputs and data.avantisfi.com are always human-decimal.
Pyth Feeds
Avantis prices flow through Pyth, never Chainlink directly for entry / settlement. Two paths:
Agents do not normally call Pyth directly — tx-builder fetches the update bytes for
/margin/update and /tpsl/update. Override via priceUpdateData + priceSourcing only when you have a fresh blob cached and want a fully offline call.
On-Chain Trade Tuple
Order matches the on-chain ITradingStorage.Trade struct. Useful when reading raw events or debugging:
Trading.openTrade(t, type, slippageP) — type is the OpenLimitOrderType enum from Step 4 — Open A Trade; slippageP is × 10^10 percent.
Events Worth Indexing
If your agent indexes Avantis logs (rather than polling APIs):orderId from MarketOrderInitiated (or just the txHash) is what to feed into /v2/market-order-initiated/status/<txHash>.