Problem
When placing limit orders for sub-dollar tokens (e.g. ARB → USDC), SellAmount shows a massive base-unit number like "230,000,000,000..." instead of human-readable amounts. Users could sign orders with wildly wrong amounts.
tk ticket: sa-lhbw
Repro: Place a limit order for ARB → USDC (or any sub-dollar token).
Root Cause
Server-side code is structurally correct (summary.sellAsset.amount uses human-readable values). The bug is most likely an LLM reasoning error for sub-dollar tokens where:
- LLM passes base-unit value as
sellAmount after seeing precision: 18
orderParams.sellAmount (base unit) leaks into LLM's text response
- LLM inverts
limitPrice for sub-dollar tokens, producing enormous numbers
Fix
- Input validation — reject
sellAmount with >15 digits (defense in depth); applies to all 3 tools
- Sanity check — log WARN at >10x deviation from market price; hard error at >1000x; applies to
createLimitOrder only (stopLoss uses USD trigger price, TWAP is market-price execution)
- Schema description — explicit base-unit warning with sub-dollar token examples on
limitPrice field; never-invert note
- Reduce leakage via
experimental_toToolResultContent — filter LLM-visible tool output without affecting the UI stream (which receives the raw execute() result separately):
createLimitOrder: strip orderParams (contains sellAmount/buyAmount in base units)
createStopLoss: strip sellAmountBaseUnit, sellPrecision, buyPrecision
createTwap: strip sellAmountBaseUnit, sellPrecision, buyPrecision
- Apply fixes 1 & 3 to
createStopLoss.ts and createTwap.ts
Follow-up (separate ticket): getAssets exposes precision: 18 in its response — this is the upstream trigger that teaches the LLM about base units. Should be filtered from getAssets output.
Key Files
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts
apps/agentic-server/src/tools/stopLoss/createStopLoss.ts
apps/agentic-server/src/tools/twap/createTwap.ts
apps/agentic-server/src/routes/chat.ts
Acceptance Criteria
Problem
When placing limit orders for sub-dollar tokens (e.g. ARB → USDC), SellAmount shows a massive base-unit number like "230,000,000,000..." instead of human-readable amounts. Users could sign orders with wildly wrong amounts.
tk ticket:
sa-lhbwRepro: Place a limit order for ARB → USDC (or any sub-dollar token).
Root Cause
Server-side code is structurally correct (
summary.sellAsset.amountuses human-readable values). The bug is most likely an LLM reasoning error for sub-dollar tokens where:sellAmountafter seeingprecision: 18orderParams.sellAmount(base unit) leaks into LLM's text responselimitPricefor sub-dollar tokens, producing enormous numbersFix
sellAmountwith >15 digits (defense in depth); applies to all 3 toolscreateLimitOrderonly (stopLoss uses USD trigger price, TWAP is market-price execution)limitPricefield; never-invert noteexperimental_toToolResultContent— filter LLM-visible tool output without affecting the UI stream (which receives the rawexecute()result separately):createLimitOrder: striporderParams(containssellAmount/buyAmountin base units)createStopLoss: stripsellAmountBaseUnit,sellPrecision,buyPrecisioncreateTwap: stripsellAmountBaseUnit,sellPrecision,buyPrecisioncreateStopLoss.tsandcreateTwap.tsFollow-up (separate ticket):
getAssetsexposesprecision: 18in its response — this is the upstream trigger that teaches the LLM about base units. Should be filtered fromgetAssetsoutput.Key Files
apps/agentic-server/src/tools/limitOrder/createLimitOrder.tsapps/agentic-server/src/tools/stopLoss/createStopLoss.tsapps/agentic-server/src/tools/twap/createTwap.tsapps/agentic-server/src/routes/chat.tsAcceptance Criteria
experimental_toToolResultContentstrips base-unit fields from LLM-visible output on all 3 tools; UI stream unaffected