Onchain OS DEX Strategy (Phase 1)
4 P0 subcommands that wrap the Agentic Wallet limit-order surface —
,
,
,
. SA activation (Trader Mode upgrade / re-upgrade) is performed transparently by the CLI when the BE returns
; the skill does not need to expose that detail.
Pre-flight Checks
Read
../okx-agentic-wallet/_shared/preflight.md
. If that file does not exist, fall back to
. Strategy endpoints require an authenticated Agentic Wallet session — confirm login before running any subcommand.
Display labels & output language (single source of truth)
This section is the canonical rule for user-facing strings. Every other section in this skill defers to it.
Canonical Display labels — the only strings the agent may surface to the user. The CLI returns these directly (
) for
; for
the agent looks them up from the §
and §
tables below.
| Surface | Canonical EN Display labels |
|---|
| (4 values) | / / / |
| (9 values) | / / / / / / / / |
Translation rule — match the user's conversation language. Display labels above are canonical English. When the user converses in another language, the agent translates the label at output time to match the conversation language.
Never (these rules apply everywhere in this skill):
- mix two languages in one label (pick one — never render the English label and a translation side by side),
- expose the underlying enum name (, , , …) to the user,
- expose the underlying CLI flag value (, , , , …) to the user,
- pass through the CLI's raw verbatim when the user is conversing in a non-English language — translate it.
Notes:
- CHASE_HIGH renders as in English (not "Chase High").
- SPEEDING_UP (-4) was removed 2026-05-08 — not a valid filter or display value.
Boundary vs
| User intent | Skill |
|---|
| "Swap X for Y now" / "Buy 0.5 ETH with USDC" | (market order, immediate execution) |
| "Buy ETH if it dips to $2000" / "Sell when ETH hits $5000" / "Take profit at X" / "Stop loss at Y" | this skill (price-triggered limit order) |
| "Cancel my pending order" | this skill |
| "What limit orders do I have?" | this skill |
If the venue is named explicitly (Uniswap, PancakeSwap, Raydium, Curve, ...) → re-route to
. This skill is for OKX-aggregated limit orders only.
Command Index
1. onchainos strategy create-limit
Place a single price-triggered limit order.
onchainos strategy create-limit \
--chain-id <id|alias> \
--from-token <address> \
--to-token <address> \
--amount <decimal-string> \
--direction <buy|sell> \
--trigger-price <usd> \
[--current-price <usd>] \
[--slippage <value>] \
[--mev-protection <on|off|default>] \
[--expires-in <secs>]
| Flag | Required | Notes |
|---|
| Y | Chain id or alias: , , , , , |
| Y | Sell-side token contract address |
| Y | Buy-side token contract address |
| Y | Amount of to sell (string, no precision loss) |
| Y | or (case-insensitive). Strategy type is derived from + + the current market price; the agent does not pass a strategy type explicitly. |
| Y | USD trigger price. Required for strategy type derivation. |
| N | Current USD price of the comparison token (to-token for , from-token for ). When omitted the CLI fetches it via . Pass it to skip the extra HTTP round-trip when the agent already retrieved the price for the confirmation page. |
| N | Slippage tolerance in percent. Default (= 15%). Pass the percent as a plain number — the CLI converts to BE wire format (divides by 100, e.g. → ). When the user says "slippage 20" / "slippage 20%" / "use 20% slippage" — all map to . |
| N | Tri-state value: / / (default = ). → (MEV protection ON), → (OFF), → (CLI does not opt in or out; BE picks). |
| N | Order TTL in seconds. Default 604800 (7 days) — see §Default order expiry. |
Output (JSON, always — the CLI has no human-format mode):
json
{
"ok": true,
"data": {
"orderId": "<id>",
"status": <int>,
"statusLabel": "<label>",
"estimatedWaitTime": <int|null>,
"eventCursor": "<string|null>"
}
}
Solana orders return — the order is queryable immediately; for all other chains the agent follows §Async wait pattern (fixed 3-second sleep before re-querying).
Default order expiry
Phase 1 BE default =
7 days (
seconds). This is the single source of truth — everywhere else in this skill that mentions "7 days" (the §Two-step confirmation expiry note, the §list "Expire after" column note, etc.) derives from here. If BE changes the default, update this section and propagate to the other mentions.
Slippage interpretation reminder (no echo from CLI):
input is in
percent units —
= 0.05% (wire
), NOT 5%. To set 5% slippage, pass
. The skill / agent should convey this to the user at input time; the CLI itself does not echo a confirmation line.
Supported chains (Phase 1, locked)
Strategy orders are only supported on these 6 chains. Any other chain MUST be rejected upfront by the agent — do not call
and do not even open the Step 1 confirmation.
| chainIndex | Name | aliases |
|---|
| 1 | Ethereum | , , |
| 56 | BSC | , |
| 196 | X Layer | , |
| 501 | Solana | , , |
| 8453 | Base | , |
| 42161 | Arbitrum | , , |
Pre-flight rule (agent): when the user mentions a chain, resolve it to its chainIndex and check this list. If the chain is
not in the table (e.g. Polygon
, Optimism
, Avalanche
, Linea
, Sui
, Tron
, ...), respond directly with:
Strategy orders are only supported on Ethereum / BSC / X Layer / Solana / Base / Arbitrum right now.
is not supported — pick one of these to continue.
Do NOT proceed to Step 1 confirmation. Do NOT call the CLI. The CLI also defends against this (validates against the same 6-chain whitelist before BE), but the agent catching it earlier saves a round trip and gives a clearer message tied to the user's exact phrasing.
enum (BaseOrderStrategyTypeEnum, locked)
| Int value | Enum name | Default direction | CLI value | Display label | Semantics |
|---|
| 2 | BUY_DIP | BUY (0) | | Buy Dip | Buy when market price falls to trigger |
| 3 | TAKE_PROFIT | SELL (1) | | Take Profit | Sell when market price rises to trigger |
| 4 | STOP_LOSS | SELL (1) | | Stop Loss | Sell when market price falls to trigger |
| 5 | CHASE_HIGH | BUY (0) | | Buy Above | Buy when market price rises above trigger |
The Display label column is the only user-facing string — see §Display labels & output language for the cross-cutting rule. The agent never sees, computes, or passes the
integer; the CLI maps everything internally.
Strategy type derivation (CLI-owned; agent uses table only for display)
is
fully derived inside the CLI from
(--direction, --trigger-price, current market price)
. The agent must NOT pass a strategy type — there is no
flag. The same table is reproduced here so the agent can compute the
Display label for the Step 1 confirmation page without re-deriving the wire integer.
| Direction | trigger vs current | Inferred strategyType | Display label |
|---|
| buy | trigger < current | BUY_DIP (2) | Buy Dip |
| buy | trigger ≥ current | CHASE_HIGH (5) | Buy Above |
| sell | trigger > current | TAKE_PROFIT(3) | Take Profit |
| sell | trigger ≤ current | STOP_LOSS (4) | Stop Loss |
Equality is folded into the "aggressive" side (CHASE_HIGH / STOP_LOSS) — same rule the CLI enforces.
Agent flow:
- Parse direction (buy / sell) from user intent ("buy" / "ape in" / "snap up" → buy; "sell" / "take profit" / "stop loss" / "exit" → sell). Passed verbatim as .
- Fetch current price — call
onchainos market price --chain <chain> --address <token>
, read . For BUY direction query the to-token's current price; for SELL direction query the from-token's current price. The agent needs this for (a) Step 0 USD-value pre-flight, (b) the Step 1 confirmation page "Trigger Price vs current", and (c) computing the Display label per the table above.
- Pass to the CLI so it does not re-fetch. (If the agent omits it, the CLI fetches the same value itself — correct but one extra round-trip.)
Two-step confirmation flow (Agent must follow)
is a write operation.
The agent MUST present a confirmation summary to the user first and only call the CLI after the user explicitly confirms. The CLI itself does not gate (it calls BE directly); this contract is enforced at the skill layer.
Step 0 — Minimum order value pre-flight (must run before Step 1):
BE enforces a minimum order value of
$1 USD (returns error
100010 ORDER_AMOUNT_TOO_SMALL
otherwise). To avoid wasting a round-trip and a confirmation page on an amount that BE will reject, the agent MUST verify the from-side USD value first.
- Fetch the from-token price (USD):
- If from-token is a well-known stablecoin (USDT / USDC / USDG / USDe / DAI / FDUSD / ...): assume without an HTTP call.
- Otherwise: call
onchainos market price --chain <chain> --address <from_token>
, read as .
- Compute USD value:
usd_value = from_amount × from_price
.
- If :
-
Compute
min_from_amount = ceil(1.0 ÷ from_price)
rounded up to a reasonable display precision for the token (e.g. whole units when
; 2-4 significant digits otherwise).
-
Surface exactly this single canonical line to the user, with no extra prose — no USD-value math, no $1 threshold mention, no echo of the user's original amount, no follow-up sentence, no apology:
Minimum order amount: <min_from_amount> <from_symbol>
Translate the prefix at output time per §Display labels & output language (e.g. for a Chinese user the agent renders the same fact in Chinese). The structure stays single-line:
<localised prefix> <min_from_amount> <from_symbol>
.
-
STOP. Do NOT render Step 1. Do NOT call the CLI. Wait for the user to provide a larger
, then re-run Step 0 from the top.
- If : carry forward (Step 1's "Value" column reuses it; no need to re-fetch) and proceed to Step 1.
Example (user wants to spend 1 OKB on a chain where OKB ≈ $0.10):
- ,
usd_value = 1 × 0.10 = 0.10 < 1.0
→ fail
min_from_amount = ceil(1.0 / 0.10) = 10
- Output:
Minimum order amount: 10 OKB
- Stop. No Step 1, no extra prose.
Step 1 — Show the order summary for the user to confirm. Five top-level categories with sub-items; the agent may freely organise prose at runtime, but no category may be dropped:
| # | Category | Sub-items | Source |
|---|
| 1 | Chain | — | Human-readable chain name resolved from (Arbitrum / BSC / Solana / ...) |
| 2 | Order Type | Display label per the § table ( / / / ) — translate per §Display labels & output language | Derived per "Strategy type derivation" above |
| 3 | From token | Symbol (e.g. ); Amount (e.g. ) | Symbol from token metadata; Amount is raw value |
| 4 | To token | Symbol (e.g. ); Trigger Price (e.g. , USD-denominated); Estimated Amount (predicted to-token amount); Value (estimated USD value) | Symbol/Trigger Price direct; Estimated Amount and Value computed by the agent — see formulas below |
| 5 | Slippage | Either (user did not mention slippage) or (user explicitly said "slippage X%") | See Slippage display rules below |
Estimated Amount / Value formulas:
- Buy direction (BUY_DIP / CHASE_HIGH):
- = ÷ (in units of to-token)
- = × (if from is a stablecoin, ≈ )
- Sell direction (TAKE_PROFIT / STOP_LOSS):
- = × (in units of to-token, usually a stablecoin)
- = × (if to is a stablecoin, equals Estimated Amount)
Slippage display rules:
- User did NOT mention slippage in the conversation → display , and omit on the CLI call (the CLI default is 15).
- User explicitly said "slippage X%" / "use X% slippage" / similar → display
Slippage: User-specified X%
, and pass on the CLI call.
Structural example (display labels come from the §
/ §
tables; see §Display labels & output language for the cross-cutting rule):
1. Chain: Arbitrum
2. Order Type: Buy Dip
3. From: USDC 10
4. To:
- Symbol: ARB
- Trigger Price: $0.10
- Estimated Amount: 100 ARB
- Value: $10
5. Slippage: 15% (default)
If the trigger condition is not met within 7 days, this order auto-expires.
Reply confirm / change / cancel.
Expiry note (mandatory): After the 5 categories and before the reply prompt, the agent must surface that the limit order auto-expires 7 days after creation if the trigger never fires. Default phrasing:
If the trigger condition is not met within 7 days, this order auto-expires.
Step 2 — Handle the user's reply:
- User says "confirm" / "yes" / "submit" → call
onchainos strategy create-limit ...
with the derived in Step 1.
- User says "change amount = 5" / "set trigger to 0.08" / similar → update the corresponding field and re-render Step 1 for another confirmation.
- User says "cancel" / "abort" → do NOT call the CLI; acknowledge that the order was discarded.
Hard constraints:
- Never call until the user has explicitly confirmed.
- / are agent-side estimates derived from , not BE quotes. The realised fill amount is decided at BE execution time by slippage and aggregator routing; the agent must not present these estimates as "actual fill amounts".
- is a USD price. The agent must make this clear to the user to avoid confusion with "exchange rate = X from-token per 1 to-token".
- Never render Step 1 when Step 0's USD-value check fails. Output the single-line minimum-amount warning instead and stop — the user must restart with a larger .
2. onchainos strategy cancel
Cancel a single, batch, or all active orders. Pass exactly one of the three flags:
onchainos strategy cancel --order-id <id>
onchainos strategy cancel --order-ids id1,id2,...
onchainos strategy cancel --all
Output (JSON): {ok:true,data:{updateNum:N,estimatedWaitTime:null|n}}
.
is the count BE accepted,
not the count that reached terminal state — re-query with
after the wait.
3.
onchainos strategy list \
[--order-id <id>] \
[--status active,suspended,...] \
[--chain-id 1,501] \
[--token <address>] \
[--limit <int>] \
[--cursor <string>] \
[--strategy-mode 7]
Two modes:
- Single order: pass → GET (returns full order shape).
- Page query: omit → POST . The active wallet's addresses are auto-supplied; pass (max 100, default 100) and from the previous response's for pagination.
Flag accepts-CSV inconsistency —
and
accept comma-separated lists (BE fields are
/
, plural).
accepts a
single address only — BE schema 2026-05-09 replaced the prior
tokenAddressList: List<String>
with a singular
field. For multi-token queries, the agent calls
once per token and merges the results.
request body fields (locked)
| field | type | required | meaning |
|---|
| String | Y | Account ID, used for JWT auth. CLI auto-injects from the current session; the agent does not pass this |
| List<String> | Y | Wallet address list. CLI auto-injects from the current wallet context (EVM + SOL) |
| List<String> | N | Chain ID filter; omit to query all chains. Mapped from |
| List<Integer> | N | Status filter (enum below). CLI defaults to the 5 non-terminal codes when is omitted — see §Default status filter |
| List<Integer> | N | Order-type filter (BE §3.3 enum); not used in Phase 1 |
| List<String> | N | Exact-match filter by order ID; no dedicated flag in Phase 1 — use (detail mode) instead |
| String | N | Filter by a single token address. Mapped from . For multi-token queries, the agent calls once per token (CLI rejects CSV input with a friendly error). BE schema 2026-05-09 dropped the previous multi-string . |
| Integer | N | Page size; BE default 100, max 100. Agent must pass for default list rendering |
| String | N | Pagination cursor (Base64). Omit on first page; pass the previous response's . Mapped from |
enum (TeeSaOpenOrderStatusEnum, locked)
Full 10-state mapping — agent reads
integer and looks up the display label here:
| Int value | Enum name | CLI value | Display label | Terminal? |
|---|
| -7 | EXPIRED | | Expired | Yes |
| -3 | CANCELLING | | Cancelling | No (transient) |
| -2 | CANCELLED | | Cancelled | Yes |
| -1 | FAILED | | Failed | Yes |
| 0 | TRADING | or | Trading | No |
| 1 | COMPLETED | | Completed | Yes |
| 2 | CREATING | | Creating | No |
| 3 | ACTIVE | | Active | No |
| 4 | SUSPENDED | | Suspended | No |
SPEEDING_UP (-4) was removed 2026-05-08 — not surfaced and not a valid filter option. The Display label column is the only user-facing string; see §Display labels & output language. CLI's
already returns the display label, so just translate it per conversation language.
Non-terminal set (5):
= CANCELLING / TRADING / CREATING / ACTIVE / SUSPENDED
Terminal set (4):
= EXPIRED / CANCELLED / FAILED / COMPLETED
Default status filter (when is omitted): the CLI puts
orderStatusList=[-3, 0, 2, 3, 4]
into the request body — the 5
non-terminal states (CANCELLING / TRADING / CREATING / ACTIVE / SUSPENDED) — and BE applies the filter server-side, returning only matching orders. Terminal orders (Cancelled / Completed / Failed / Expired) are
excluded by default. Rationale: when a user asks "show my orders" they almost always mean live ones; surfacing historical terminal records pollutes the answer.
To see terminal orders the agent must pass
explicitly:
| User intent | value to pass |
|---|
| "show my completed orders" | (orderStatusList=[1]) |
| "show my cancelled orders" | (orderStatusList=[-2]) |
| "show failed orders" | (orderStatusList=[-1]) |
| "show expired orders" | (orderStatusList=[-7]) |
| "show all orders including terminal" | active,suspended,creating,trading,cancelling,completed,cancelled,failed,expired
(full 9) |
| "show my live orders" / no qualifier | (omit — uses non-terminal default) |
accepts comma-separated values; each entry is either an integer (e.g.
) or a string label (
,
,
,
,
,
,
,
,
).
Agent rendering rules (when the user asks for orders without naming a specific status)
User prompts that match this rule include: "show my strategy orders" / "list orders" / "show my limit orders" / "what orders do I have" — i.e. any general "show me my orders" intent without a status qualifier.
Steps the agent must follow:
-
Run
onchainos strategy list --limit 10
(no
) — the CLI puts
orderStatusList=[-3, 0, 2, 3, 4]
(non-terminal set) into the request body; BE applies the filter server-side and returns only matching orders.
Always pass for general "show my orders" queries; full pagination is opt-in via "next page" follow-up.
-
Render the response
as a Markdown table with
exactly these 8 columns (locked):
| Order id | Order Status | Order Type | Estimated Amount | To Token addr | Value | Trigger price | Expire after |
|---|
Per-row mapping (order matters, no extra columns):
| Column | Source | Notes |
|---|
| Order id | | — |
| Order Status | (Display label per the § table) | Translate per §Display labels & output language |
| Order Type | Display label per the § table, derived from data.list[i].strategyType
integer ( / / / ) | Translate per §Display labels & output language |
| Estimated Amount | data.list[i].toToken.tokenAmount
+ + data.list[i].toToken.tokenSymbol
| e.g. |
| To Token addr | data.list[i].toToken.tokenContractAddress
, truncated to first-6 + last-4 | EVM: ( + 4 chars + + 4 chars); Solana base58: first 6 + + last 4 |
| Value | data.list[i].toToken.tokenUsd
, formatted as | e.g. (round or 2-decimal, follow BE precision) |
| Trigger price | data.list[i].triggerInfo.triggerPrice
, prefixed with | e.g. ; if empty (trigger-rate path, not used in Phase 1) display data.list[i].triggerInfo.triggerRate
|
| Expire after | (13-digit ms UTC), converted to the user's current timezone, formatted | e.g. (semantically = createTime + 7 days by default) |
Sample row (Solana SOL→USDC take_profit):
| 17262791359882688 | Active | Take Profit | 0.2 SOL | 9xQeWv...vEjz | 16 USD | $80 | 05/15/2026 17:50:49 |
Address shortening rules:
- EVM ( prefix): first 6 chars ( + 4) + + last 4 chars
- Solana / other non-prefixed base58: first 6 + + last 4
- Strings shorter than 10 chars: do not truncate; display verbatim
Expire timezone conversion:
- from BE is a UTC millisecond timestamp
- The agent must convert to the user's current local timezone at render time (e.g. JS , Rust , or equivalent)
- Fixed format: , 24-hour clock
-
After the table, append a
single combined reminder covering pagination + status filter. Include the pagination line
only when is non-empty.
Canonical EN; the agent translates per §Display labels & output language:
Showing live orders by default (10 per page).
- Reply "next page" to load more.
- To filter by a specific state, ask for orders by their Display label — e.g. , , , . Example: "show my completed orders" → I'll re-query with that filter.
If
is empty (no more pages), drop the "next page" bullet and keep only the status-filter bullet.
-
If the user replies "next page" / similar, re-run with
--limit 10 --cursor <nextCursor>
carrying the previous response's
. Render with the same table format.
-
If the user names a specific status (any of the 9 Display labels), re-run as
list --limit 10 --status <label>
(single value) and render the same table. Drop the status-filter bullet from the reminder; keep the pagination bullet if
is non-empty.
4. onchainos strategy resume
onchainos strategy resume # auto-discover all SUSPENDED + canResume=true on active wallet
onchainos strategy resume --order-ids id1,id2 # explicit
When ids are omitted, the CLI runs
filtered to
and keeps only orders whose
flag is true; the discovered ids are then submitted to
. After resume, the agent should advise the user that orders whose trigger condition was already met may execute immediately — re-query with
to confirm.
Error code → Agent action
The CLI surfaces the BE error code in human-readable form. Map each code to a recommended next step:
| Code | Name | What the agent should do |
|---|
| 100 | REQUEST_PARAM_ERROR | Surface the BE message; ask the user to fix the offending flag |
| 10019 | INSUFFICIENT_NATIVE_GAS_BALANCE | Wallet's native token balance is below the BE-required minimum (the response msg includes , e.g. BNB on BSC). Tell the user their native gas balance is insufficient to pay this chain's gas fees and prompt them to top up — deposit from an exchange, transfer from another account, or swap a stablecoin to native via . Do NOT auto-retry. |
| 10026 | JWT_TOKEN_VERIFY_FAILED | Suggest then retry |
| 10106 | CHAIN_NOT_SUPPORT_ERROR | Tell the user the chain is not supported; suggest a supported alternative |
| 60002 | NO_ORDER_FOUND | Cancel/resume target id is wrong or already terminal — suggest |
| 60003 | LIMIT_ORDER_NO_AUTHORITY | Trader Mode may not be activated yet; the next CLI call will trigger SD-A automatically — retry once |
| 60006 | LIMIT_ORDER_OUT_LIMIT_FAIL | Pending order count is at the per-account limit (max 100); ask the user to cancel some pending orders ( or ) and retry |
| 60009 | LIMIT_ORDER_ILLIQUIDITY_ERROR | No liquidity for the pair at the trigger; suggest a different pair or wider trigger |
| 60014 | LIMIT_ORDER_EXPIRED_CANNOT_OPERATE | Order already expired |
| 60015 | LIMIT_ORDER_PENDING_CANNOT_OPERATE | Order is mid-lifecycle; wait for terminal state |
| 60017 | LIMIT_ORDER_SUCCESS_CANNOT_OPERATE | Order already completed |
| 60018 | LIMIT_ORDER_TEE_SA_VERSION_UPGRADE_REQUIRED | Transparent — CLI handles via SD-A retry; the agent should NOT see this code in normal flow. If it leaks, just retry the same command |
| 60030 | QUOTA_EXCEEDED | Account-level quota reached |
| 100005 | WALLET_ADDRESS_BLACKLISTED | Wallet address flagged by risk control; ask the user to contact support — do not retry |
| 100007 | TEE_SIGN_FAILURE | Transient TEE issue — retry once |
| 100010 | ORDER_AMOUNT_TOO_SMALL | Order value is below the BE-enforced minimum of $1 USD. Ask the user to increase so the order value clears $1, then retry |
| 100008 | TEE_SERVICE_UNAVAILABLE | TEE service is temporarily unavailable; ask the user to retry later |
| 100012 | LIMIT_ORDER_INSUFFICIENT_BALANCE | Insufficient balance; suggest checking with |
Match by integer code, not msg string. The msg text is for humans and may change.
Execution event codes (executionHistoryList[].code
)
A separate stream from the BE error codes above. Emitted by the TEE swap-trade engine while it attempts to execute an active order. Read the latest entry first; older entries are historical context.
CLI enriches each entry directly — no sidecar table needed. For every code the CLI recognises (35+ codes covering the 3xxx active series + 2xxx legacy series),
and detail responses inject three fields next to the raw
:
| Field | Source | Use |
|---|
| Catalog ( / / ...) | Internal label; do NOT surface to the user |
| Catalog — matches OKX wallet UI wording | Surface verbatim to the user (translate per §Display labels & output language) |
| Catalog | ⇒ TEE engine will not retry; stop polling and surface. ⇒ engine retries; safe to wait |
For codes the CLI does
not recognise (BE added a new code we haven't catalogued yet), the entry passes through unchanged —
/
/
are absent and the agent should surface the raw BE
field if present, or fall back to
.
Reading patterns
- Latest entry wins. Render the most recent item; older entries are historical context only.
- Repeated same code. When the same code recurs every ~10s without a appearing, the engine is in a soft retry loop. Surface the latest , mention the repeat count ("this is the 5th
No quote due to low liquidity
event"), and ask the user whether to wait, cancel, or adjust parameters.
- codes. Stop polling immediately and surface to the user; engine will not retry.
- codes that repeat 3+ times. Treat as user-actionable: suggest changing slippage / amount / pair / chain, or cancelling.
- Code with . Trade succeeded; surface and explorer link.
Action hints by hot code
The
field is the user-facing string. The agent additionally chooses one of these action hints based on
:
| code | what the agent should do |
|---|
| 0 | report success; surface + explorer link |
| 3013 | suggest topping up the from-token or recreating with smaller amount |
| 3014 | tell user to fund the chain's native fee token (SOL / ETH / BNB / ...) |
| 3015 | suggest widening |
| 3016 | non-transient — suggest different pair, smaller amount, wider trigger, or different chain |
| 3017 | engine retries; if recurring 3+ times, treat like 3016 |
| 3019 | terminal — destination token is blocklisted; order will not execute |
| 3020 | terminal — wallet address is flagged; surface explicitly |
| 3023 | recreate with longer |
Codes outside this table: read
from the CLI output.
⇒ surface and stop.
⇒ surface and wait one more cycle.
Async wait pattern
,
, and
return after the request has been
accepted, not after the order reached a terminal state. The CLI surfaces
(seconds, BE-supplied — typically 0 for Solana, ~3 for BSC, ~12 for ETH-class chains).
Agent recipe (locked):
- Run the subcommand.
- Sleep 3 seconds. A single fixed 3-second wait is enough across all supported chains in practice — empirically validated 2026-05-11. Do not read from the response and sleep by that value; the BE-supplied number is conservative and inflates the wait unnecessarily (especially on ETH-class chains).
- Re-query with
onchainos strategy list --order-id <orderId>
to read the final state.
- If still pending after the first re-query, surface the partial state to the user; do not loop indefinitely.
Do not run a long polling loop. The CLI is not designed for that; the BE backs the order finalisation off-chain and one targeted re-query is sufficient in normal conditions.
SA activation transparency
Trader Mode upgrade / re-upgrade is performed transparently by the CLI:
- On or , if the BE returns code (), the CLI calls the Agentic Wallet attestation endpoints ( → ed25519 sign with the session key → ), then retries the original op once. On success the user sees followed by the normal command output.
- The agent should not ask the user to "activate Trader Mode" first — the CLI does it on demand.
- If activation fails, the original command aborts and the activation error is surfaced. Suggest to inspect the session.
Output format conventions
All strategy subcommands always emit the standard onchainos JSON envelope
{ok: true, data: { ... }}
on stdout. There is no
flag — strategy CLI is agent-facing, so structured JSON is the only output and the agent renders any user-visible tables (e.g. the §
8-column Markdown table) from that JSON.
Phase 1 limitations
| Item | Phase 1 status |
|---|
| Symbol → address resolution for / | Not in scope; pass token addresses directly |
| Custom preset (advanced fee tiers, dexId filter) | Default preset only — Phase 2. MEV protection is already supported via --mev-protection <on/off/default>
(see §1 flag table). |
| Events stream / cursor consumption | is surfaced verbatim; no consumer in Phase 1 |
| source-channel filter (KD-009) | Pass-through to BE default; CLI does not pre-filter |
| Multi-account batch | Out of scope; CLI uses the active account only |
| (PRD §5.1) | Intentionally not implemented. SA activation / expiry is handled transparently inside the 60018 (UPGRADE_REQUIRED) flow — the CLI runs SD-A and retries silently. The agent does not need to query SA state up-front; just call the intended subcommand and let the CLI handle activation on demand. |