ODEI
DOCUMENTATION Each page names the release it was checked against.
Docs Agent docs Checked 2026-11-06
Tools · Wallet

Wallet: propose, never sign

Five tools. Your AI picks a recipe or builds exact calls. ODEI verifies, simulates and prepares fees. The owner approves in ODEI. The AI never signs or sends.

Live
  • odei_wallet_state, odei_wallet_read, odei_wallet_propose, odei_wallet_status, odei_wallet_cancel on 8 networks.
  • Recipes (list in /docs/capabilities.json), exact calls, CoW typed data, ODEI Orders.
Not available
  • Auto is coming soon; today the owner approves each operation in ODEI.
  • Exact-output swaps and quotes. Passing amountOutAtomic refuses with compact_wallet_recipe_exact_out_off.
  • Swap after a bridge. Uniswap v3 liquidity recipes.
  • Owner-only recipes such as borrowing. An agent gets recipe_unknown.
  • An agent proposing to run a Network Alpha. Only the owner's own Run in ODEI works.

Checked against release f649e1b5ac40, 2026-11-06. Compare with /health.

The five tools

ToolDoesRequiredAccess
odei_wallet_stateWallet summary, recipe ids, autoStatenoneeconomy.read
odei_wallet_readChain reads, approvals, quote, orders, statementchainIdeconomy.read
odei_wallet_proposePropose a real operation; returns reviewUrlrequestId, chainIdeconomy.read, capital.propose, capital.plan
odei_wallet_statusWhat actually happened to one proposalpass operationId or proposalIdeconomy.read
odei_wallet_cancelWithdraw unsigned operations, only when the owner asksone selectoreconomy.read; direct cancel, filters and preview need capital.propose

For a wallet task, call odei_wallet_propose first; chainId is enough. Read state or chain first only when you need context. One-page guide: odei_overview {"view":"guidance","forTool":"odei_wallet_propose"}.

Networks

chainIdNetworkCoin
1EthereumETH
10OptimismETH
56BNB ChainBNB
137PolygonPOL
4663Robinhood ChainETH
8453BaseETH
42161ArbitrumETH
43114Avalanche C-ChainAVAX

Pass chainId as an integer or decimal string. ODEI decodes and simulates each call and joins several into one transaction, except on Avalanche C-Chain. Pass networkId only when several registered networks share a chainId; needs_input returns candidates. Other refusals: compact_wallet_chain_unsupported, compact_wallet_chain_invalid, needs_network.

Who approves

Auto is coming soon; today the owner approves each operation in ODEI. Your AI gives the owner reviewUrl and cannot approve for them. autoDecision on a propose or status result, when present, says why an operation waits. Relay its reason.

Never split work to avoid review.

Reading an Auto decision

These fields stay on results so existing clients keep working. While Auto is off, every operation waits for the owner.

Before proposing, read odei_wallet_state.autoState, and autoAdmissible on a swap quote (a hint from fixed-pool routes). After proposing, trust odei_wallet_status autoDecision. A plain awaiting_owner propose result has no autoDecision, so status is the reliable source. ownerApprovalRequired on a propose result is always true, including operations Auto is running. Do not read it as state.

autoDecision is {decision, reasonCode, reason}, with decision ran, waits or unknown.

  • ran is Auto's approval, not the result, and only an operation from before Auto went off can read it. If it cannot be sent, status shows awaiting_owner.
  • reason ends with your next step while the operation waits. Relay it.
  • auto2_not_judged means Auto is not on for that wallet and network.
Next step in reasonSeen on codes such as
Give the owner reviewUrlAnything without a more specific step
Or cancel and propose again in a few minutes with a NEW requestIdsimulation_failed, price_unverified
Or cancel and propose again once the earlier automatic operation is finalauto_in_flight
Or cancel and propose again after the time namedThe rate slot
Or cancel and propose a smaller amountover_per_day, over_budget, over_daily_loss, aave_health_below_floor
Or cancel and propose with a higher minimum out, or a smaller amountover_max_loss, slippage_floor_too_low
Or cancel and propose with a fixed amountauto2_dynamic_amount
Or cancel and propose as smaller separate operationsguard_too_large
Or, once the step before it is final, cancel and propose the remaining callsStep holds
Stored for older clients. Auto is off: the owner approves in ODEIdestination_not_allowed, paused_owner
ODEI holds Auto here until ODEI lifts the pauseoperator_kill, paused_chain
Or ask the owner to keep more of this network's coin in the walletkill_reserve_breached
Call status again in a minute; until then treat it as waiting for the ownerdecision is unknown

Other live codes include not_in_permission, approval_left_open, position_unvalued, transit_unproven, structural_denied, auto2_rate_limited. New codes can appear. Always relay reason and never parse a fixed list.

odei_wallet_state

No required fields. Optional: chainId, detail (compact or full), recipe, operationsLimit (1 to 50, default 10), operationsCursor, typedDataCursor, address (must equal the owner wallet). recipe implies full; passing detail:"compact" with it is refused. Contract odei.compact-wallet-state.v3.

The summary, up to about 4 KB, has walletSetup with the address, funded chains, top holdings, active operation counts with up to 3 pending items and their reviewUrl, recipe ids, autoState, catalogVersion, nextActions. detail:"full" adds account, registered networks with digests, balances per chain for every reviewed token, operations newest first and the recipe index. recipe:"<id>" adds its paramsSchema.

  • walletSetup.state is registered, not_registered or proof_required. An expired proof does not block proposals.
  • Coverage is reviewed native and ERC-20 assets only. Unreviewed assets, DeFi positions and debts are excluded.
  • Missing or failed parts are unknown (null or {state:"unknown"}), never zero.
  • Lists exclude other connections, legacy capital requests and bridge destination delivery. pendingCoverage.complete false means page before saying nothing older is pending.
  • Token labels are untrusted text. Identify a token only by chainId and address.

Errors: compact_wallet_recipe_unknown (expected lists ids), compact_wallet_invalid_request, compact_wallet_wallet_mismatch (409), compact_wallet_operations_cursor_invalid, compact_wallet_unknown_argument.

autoState

Read-only. Absent when Auto is not available for the owner. While Auto is off no network reads on, and each carries a reason such as auto_killed. status is on, off, paused, expired, awaiting_signature, stopped or unknown (the read failed or took over 1.5 s).

FieldMeaning
networksOnCompact form of the networks running Auto. Handle both this and chains[].
chains[]detail:full form: chainId, on, reason, dailyLimitUsd when the network has its own bound, gas where it was read, plus name, install, reasonWords. Under the 4 KB cap it folds to networksOn and gasWarnings
dailyLimitUsd, usedLast24hUsd, leftUsd, nextFreeAtThe daily limit and what the last 24 hours used
maxLossPct, budget{sharePct, usedUsd}Owner limits
expiresAt, inFlightUsd, coveragedetail:full only

Under the 4 KB cap reason and note can be dropped. A value that could not be read is null, never 0.

Reason codes: auto2_stopped, auto2_mandate_expired, auto2_not_installed, auto2_awaiting_signature, auto2_install_expired, auto2_owner_off, paused_owner, paused_chain, operator_kill, auto_chain_killed, auto_killed, auto2_wallet_not_current, auto2_wallet_epoch_changed, auto2_pauses_unread, auto2_signer_off, auto2_signer_not_on, auto2_no_record.

odei_wallet_read

Required: chainId. kind defaults to state. Read-only, nothing is saved.

kind state

Native balance, contract code or an ABI eth_call, 1 to 16 queries. Results are raw bytes with provenance and evidence.observedAt (server time; use it for deadlines), not verified semantics. Report them as observed values only. Omit block for a checked head and reuse the returned block for related reads.

{"chainId":8453,"queries":[{"id":"a","kind":"call","address":"0x...","data":"0x..."}]}

Queries: {id, kind:"native-balance"|"code", address} or {id, kind:"call", address, data, from?, value?, gas?, decode?}. Call defaults: from the owner wallet, value "0", gas "3000000", decode null. decode is {kind:"abi-uint", bits, wordIndex}.

Refusals: compact_wallet_invalid_request, needs_wallet, needs_permission, needs_network, needs_input, needs_retry with retryAfterMs and maxAttempts 3.

kind approvals

{chainId, kind:"approvals"}. Lists token approvals for one network from reviewed spenders plus ODEI records. It is not a full scan. Each row carries a ready erc20-revoke-batch proposal. Unavailable or partial reads say approvals are unknown, not none. Unused signed permits are not listed; the owner cancels them in ODEI. An approval is revoked only once a later read shows 0.

Result: readAt, scope, coverage, checked, partial, truncated, recordsTruncated, items[], revokeBatch, notes, signedPermits, ownerUrl. Error: compact_wallet_approvals_unavailable (503).

kind quote

{"kind":"quote","chainId":8453,"recipe":"best-swap","params":{"tokenIn":"...","tokenOut":"...","amountInAtomic":"..."}}

chainId 10, 8453 or 42161. recipe must be best-swap. Optional maxSlippageBps. Saves nothing. About one new price per 2 s and 30 per 10 minutes per connection; an identical read inside 2 s returns the same answer. Contract odei.agent-swap-quote.v1. To trade, call odei_wallet_propose with recipe best-swap, the same chainId and params, and a NEW requestId. ODEI compares again.

Refusals: compact_wallet_recipe_invalid, compact_wallet_recipe_params_invalid, compact_wallet_recipe_chain_unsupported, needs_retry with error.code quote_rate_limited, compact_wallet_recipe_exact_out_off.

kind orders

{chainId, kind:"orders"}. This connection's ODEI Orders: open (up to 20), recent final (5 latest) and otherOpenOrders, a count of other open orders on the wallet. Each row: id, chainId, coin, kind, line, state, attentionReason, schedule and lastSlice for repeat orders, watch{price, ageSeconds}, triggeredAt, cardOperationId, fillTxHash, fillAmountOut, filledAt.

kind statement

{kind:"statement", chainId, period?, asset?, cursor?, limit?}. Balance history for the owner wallet: what moved, who asked, what is not explained. period is 24h, 7d, 30d or all. asset is a key like native:8453 or erc20:8453:0x.... limit 1 to 25. Omit queries, block and networkId.

Read from ODEI's stored history, never a provider sync. Other connections appear as another_connection, the caller as this_connection. Totals exclude pending, unverified and unsolicited activity. null means unknown, not zero. BNB Chain, Avalanche and Robinhood Chain report ODEI activity only. Native ETH received from contracts on Base, Arbitrum and Optimism is not listed yet. Contract odei.wallet-statement.v1.

odei_wallet_propose

Proposes a real wallet operation, not a draft. Three shapes:

  1. recipe + params. Preferred when one fits.
  2. kind:"calls" with calls [{to, data, value}], to any contract.
  3. kind:"typed_data" with typedData: a CoW order or cancellation only.
{"requestId":"req_<32 hex>","chainId":8453,"recipe":"wrap-unwrap","params":{"direction":"wrap","amountAtomic":"1000000000000"}}

Required: requestId, chainId. Optional: networkId, kind, semantics, accountUpgrade, calls, typedData, presentation, intent, validity, limits, recipe, params, continues.

Always relay ownerMessage verbatim on awaiting_owner; it contains reviewUrl unchanged. Keep warnings, riskFlags, recipientNotices, recipientGuard and feeNotice. The result also carries network, operationId (meop_) or proposalId (mesp_), revision, semantics, semanticsChosen, ownerApprovals, sequenceTiming, preparation, fees, simulatedChanges, mismatch, notices.

Result states

StateWhat to do
awaiting_ownerRelay ownerMessage. Never say approval or fees happen in chat.
needs_retryWait retryAfterMs, same call, at most maxAttempts.
blockedretryable false. Follow message. See blocked reasons.
atomic_unavailableNothing was split or sent. Propose with semantics:"sequential" and a NEW requestId, except atomicOnly recipes.
needs_networkNo RPC setup is needed. Give the owner setupUrl.
needs_walletRelay ownerStep exactly. Never suggest creating a wallet; use setupUrl only if the owner says they never set one up.
needs_inputPick a networkId.
needs_permissionGive the owner ownerStep and ownerUrl, then retry.
expiredPropose again with a new requestId.
continuedThe operation was continued. Follow continuedBy.
An operation outcomeThe requestId replays something already moving. See outcomes.

requestId

Generate one requestId per proposal: req_ + 32 lowercase hex.

  • After a timeout or needs_retry, retry with the same requestId and identical arguments. ODEI reuses the operation and never duplicates it.
  • Any change of arguments needs a NEW requestId, else compact_wallet_request_conflict (409, retryable false). expected may carry the saved operationId, revision and reviewUrl.
  • A recipe re-reads the live quote and deadline on every call, so a later retry of a recipe can hit request_conflict. Treat the earlier proposal as standing, or use a NEW requestId for a fresh quote and optionally cancel the old one.
  • A retry of an operation that already moved reports that operation's actual state and saves nothing new.
  • A replay of an operation whose prepared review lapsed returns awaiting_owner with a working reviewUrl and notice review_reprepared_on_open. Do not propose again.
  • After balance_insufficient, once funded, the same requestId is correct (retryCondition balance_sufficient, reuseRequestId true). Other blocked reasons need a NEW requestId after the fix.

Exact calls

Proposes exact contract calls in order. One call is single. Several default to atomic: one owner Approve for the batch, all or nothing. semantics:"sequential" means one Approve per step, each next Approve available once the previous step is final.

A plain wallet is upgraded to one-signature in the same transaction (EIP-7702, bytecode-verified Kernel 0.3.3, reason atomic_with_upgrade). Address, key and funds are unchanged, and the owner can turn it off. accountUpgrade:"never" gives sequential.

FieldRule
calls[{to, data, value}]. to is an address or null. data is hex, "0x" for a plain native transfer. value is wei as a base-10 string, "0" when none.
semanticssingle, sequential, atomic
accountUpgradeauto, never
presentation{title?, description?, action?}. Title at most 160, description at most 2000 chars, action 2 to 8 segments such as swap.exact_in. Title names only these calls.
limits{maxGas?, maxFeePerGas?, maxPriorityFeePerGas?, maxGasPrice?, maxTotalFeeWei?}, only if the owner gave a cap
validity{expiresAt} in UTC with exactly three ms digits and Z. At least 3 minutes for the owner. It is the last time the owner can approve and cannot be extended.

Refusals: compact_wallet_calls_invalid, compact_wallet_semantics_invalid, compact_wallet_calls_fields_invalid, compact_wallet_address_invalid, compact_wallet_address_checksum_invalid, compact_wallet_hex_invalid, compact_wallet_validity_window_too_short (carries minWindowMs), compact_wallet_presentation_invalid, compact_wallet_account_discovery_unavailable (503, retryable), compact_wallet_relay_raw_deposit (use relay-topup). Notices: recipe_available, approval_only, presentation_defaulted, presentation_mismatch, presentation_action_ignored, validity_from_quote.

Continuing an operation

continues:{operationId, revision?} with a NEW requestId proposes the next step of this connection's own earlier operation on the same chain, for example the swap after its approval. Exact calls only. The parent must be owner-signed with its signed steps final. If the parent used intent, this call must too. A signed parent that is not final answers needs_retry. An operation continued is final with outcome continued; its review link is no longer used. Follow continuedBy. Error: compact_wallet_continues_invalid.

Post-conditions

intent {queries (1 to 32), predicates (1 to 64), effects? (0 to 32), quote?}. Exact calls only, never with a recipe. Omit it rather than invent one. Never compute sourceDigest or plannedCallsDigest yourself.

Predicate kinds: uint-after, uint-interval-delta (signed; a debit is negative), bytes-after. Effect kinds: maximum-debit, minimum-credit, allowance-after, each naming supportingPredicateIds. intent.quote needs expiresAt. Full schema: page 1 of input-schema. Error: compact_wallet_intent_invalid.

Typed data

A CoW order or cancellation only. ODEI posts it to the CoW orderbook once the owner signs. The agent never receives a signature. Every other EIP-712 message, including permits and Permit2, is refused; propose exact transaction calls instead. Prefer recipe cow-limit-order.

typedData {domain, types, primaryType, message} as eth_signTypedData_v4 JSON: integers as decimal strings, domain.chainId equal to chainId, message owner equal to the wallet. One message per proposal. Returns proposalId (mesp_) and submission odei_posts_after_owner_signs. Track with odei_wallet_status {proposalId}: signatureState, signatureWithheld, orderSubmission, cowOrder.

Refusals: compact_wallet_typed_data_fields_invalid, compact_wallet_typed_data_invalid, compact_wallet_typed_data_unsupported, compact_wallet_flagged_address_refused. A past deadline is refused.

Recipes

Three lists differ. The propose tool description is a static index for every owner. odei_wallet_state recipes is the per-owner view, and can omit an engine recipe when a runtime switch is off; a recipe the index names can then refuse with recipe_unknown at call time. Some recipes are proposable by id only. Read paramsSchema with odei_wallet_state {"recipe":"<id>"}. Unknown params are rejected with the allowed list.

RecipeWhat it doesChainsRequired in paramsOptionalNotes
wrap-unwrapWrap the native coin, unwrap it, or both in one atomic batch.All 8direction, amountAtomic
erc20-transferSend an exact amount of an ERC-20 or the native coin to one recipient.All 8token, to, amountAtomic (or amount)to may be an ENS name or Basename.
uniswap-v3-swapSingle-pool swap: approve exactly the amount, swap, revoke, in one atomic batch.All 8tokenIn, tokenOut, amountInAtomicfee, minimumOutAtomic, slippageBps, deadlineSecondsOutput limited to the chain's reviewed native, wrapped-native and stablecoin assets.
camelot-v3-swapExact-input ERC-20 single-pool swap, atomic only. A pool price boundary can leave a partial fill; unspent input stays in the wallet.42161tokenIn, tokenOut, amountInAtomicslippageBps, deadlineSecondsOutput only Arbitrum's reviewed WETH or USDC.
balancer-v2-swapExact-input Vault swap through an allowlisted pool, atomic only.1, 137, 8453, 42161poolId, tokenIn, tokenOut, amountInAtomicslippageBps, deadlineSecondsRegistered ERC-20 only; use wrapped native.
balancer-v2-batch-swapExact-input batch swap through verified allowlisted pools, atomic only.1, 137, 8453, 42161swaps (1 to 8)slippageBps, deadlineSecondsBase units only.
best-swapODEI compares on-chain routes and aggregator quotes, decodes and re-simulates each, and proposes the best verified route as one atomic batch. Output goes to the owner wallet only.10, 8453, 42161tokenIn, tokenOut, amountInAtomic (or amountIn)maxSlippageBps, minOutAtomicSee the section on best-swap.
cow-limit-orderSell-kind CoW Protocol limit order. ODEI posts it once the owner signs.1, 56, 137, 8453, 42161, 43114sellToken, buyToken, sellAmountAtomic, buyAmountAtomicvalidForSeconds, partiallyFillableERC-20 only. No orderbook on Optimism.
odei-orderCreate or cancel an ODEI Order: limit, take profit, stop loss, trailing stop or repeat buy or sell.8453, 42161action (plus the create or cancel fields)See the section on ODEI Orders.
cctp-bridgeBurn native USDC with Circle CCTP V2 forwarding; Circle mints to the same wallet on the destination.1, 10, 137, 8453, 42161, 43114destinationChainId, amountAtomicmaxFeeAtomic, finalityA burn is not delivery.
cctp-receiveMint on the destination when automatic forwarding has not delivered.1, 10, 137, 8453, 42161, 43114sourceChainId, sourceTransactionHashnonceProposable by id. Offered from bridgeDelivery.manualCompletion.
best-bridgeODEI compares bridges for native USDC or native ETH and proposes the one that delivers the most after every fee, as one atomic batch.1, 10, 8453, 42161destinationChainId, amountAtomictoken, tokenOut, recipient, recipientAddress, provider, expectedProvider, expectedMinOutAtomicatomicOnly. Listed only while the bridge comparison is on.
relay-topupTop up the gas token of BNB Chain, Polygon and Robinhood Chain through Relay, as one atomic card.1, 10, 8453, 42161legs (1 to 3)token, recipient, recipientAddressUp to $1,000 in one card. The recipient must be the owner's wallet.
debridge-cancelCancel the owner's own deBridge order that no solver filled, refunding the owner on the source.1, 10, 56, 137, 8453, 42161sourceChainId, sourceTransactionHash, orderIdProposable by id. Offered by the bridge delivery read. Manual only.
lido-stakeStake ETH for stETH through Lido in one call.1amountAtomic
aave-supply-withdrawSupply to Aave v3, or withdraw an exact amount or everything.1, 8453, 42161action, asset, amountAtomicThe supplied aToken amount is an estimate.
aave-repayRepay variable Aave v3 debt up to the cap. Debt may remain as interest accrues.8453, 42161asset, amountAtomicmax is the debt read now +0.1%, capped at the wallet balance.
spark-supply-withdrawSparkLend supply and withdraw on Ethereum.1action, asset, amountAtomicDAI, USDS and WETH only.
spark-repaySparkLend repay on Ethereum.1asset, amountAtomicDAI, USDS and WETH only.
erc4626-deposit-withdrawDeposit or withdraw exact underlying assets through verified Fluid fTokens.1, 8453, 42161action, vault, amountAtomicDespite the name, this is not a general ERC-4626 recipe. Base has no verified USDT fToken.
best-yieldODEI reads USDC rates of every venue it can build on, simulates the deposit and exit, ranks by what is kept over the hold, and proposes one atomic batch.1, 8453, 42161asset, amountInAtomicholdDays, choice, maxTier, preferAutoatomicOnly. Variable on-chain APY; rewards are not counted. Listed only while its switches are on.
yield-withdrawWithdraw USDC from a supported deposit back to the owner wallet.1, 8453, 42161providerId, market, asset, amountAtomicatomicOnly. max only where the source supports it now.
aave-hedgeMake part of an ETH position price-neutral in one transaction: supply, borrow WETH, sell it for USDC through ODEI Best Execution, supply the USDC.8453, 42161ratioBpsasset, ethAtomic, amountAtomic, maxSlippageBpsRefused if final Aave health would be below 1.50. atomicOnly.
aave-hedge-adjustMove an open hedge to 50%, 80% or 98%.8453, 42161targetRatioBpsasset, maxSlippageBpsatomicOnly.
aave-hedge-unwindClose a hedge, optionally buying back.8453, 42161noneasset, buyBack, unwrap, maxSlippageBpsatomicOnly.
erc20-revokeSet one ERC-20 or Permit2 allowance to zero.All 8token, spenderamountAtomic (must be 0), approvalKindProposable by id.
erc20-revoke-batchSet up to 8 allowances to zero.All 8items (1 to 8)Proposable by id. Rows from kind approvals carry a ready proposal.

atomicOnly recipes never split into sequential steps. erc20-permit is listed with proposable:false; connectors cannot use it. Recipe cards larger than ODEI can save are refused with no retry. Refusals carry a cause and a next step in message: compact_wallet_recipe_unknown, compact_wallet_recipe_chain_unsupported, compact_wallet_recipe_params_invalid, compact_wallet_recipe_fields_invalid (with a recipe omit calls, typedData, intent, continues), compact_wallet_recipe_kind_unsupported, compact_wallet_kind_invalid, compact_wallet_recipe_build_failed.

Amounts, symbols and names

Recipe params take base units in XAtomic fields, or X as "100" or "100 USDC" for amount, amountIn, minimumOut, sellAmount, buyAmount, maxFee. ODEI converts with on-chain decimals and never rounds. A token field may be a reviewed symbol for that chain. An unknown or ambiguous symbol is refused with candidates, never guessed. erc20-transfer to may be an ENS name or Basename; ODEI resolves and checks it and refuses on mismatch. Report result.recipe.params.

Human amounts: wrap-unwrap, erc20-transfer, cctp-bridge (amount, maxFee), lido-stake, aave-supply-withdraw, aave-repay, spark-supply-withdraw, spark-repay, erc4626-deposit-withdraw (amount); uniswap-v3-swap (amountIn, minimumOut); camelot-v3-swap, balancer-v2-swap, best-swap (amountIn); cow-limit-order (sellAmount, buyAmount). Base units only: balancer-v2-batch-swap, cctp-receive, erc20-revoke, erc20-revoke-batch.

best-swap

ODEI compares routes and proposes the best verified one. The minimum received is enforced in calldata. Name no fixed source list; read rows[].providerName from the quote. On swaps of 500 USD or more on Base and Arbitrum, ODEI Router also competes. Native ETH in keeps 0.001 ETH for fees, so balance_insufficient can appear with a nearby balance. Listed per owner; read odei_wallet_state recipes. detail:"full" status of a final confirmed swap adds fillReport.

maxSlippageBps 0 to 300, default 50. Refusals: compact_wallet_recipe_best_swap_refused, compact_wallet_recipe_best_swap_unavailable, compact_wallet_recipe_no_route, compact_wallet_recipe_offer_changed, compact_wallet_recipe_exact_out_off.

ODEI Orders

Recipe odei-order. Not the same thing as service orders in odei_orders. Chains 8453 and 42161. Answers are not compact_wallet_ states: order_saved, order_cancelled, order_unchanged.

Create: action:"create", chainId inside params as an integer (8453 or 42161, equal to the top-level chainId; without it the call is refused as order_chain_unsupported), amountAtomic (the token sold: the coin for sells, USDC for a buy), legs (1, or take profit plus a stop), optional coin (WETH or cbBTC on Base, WETH or WBTC on Arbitrum, default WETH), expiresInSeconds (3600 to 2592000, default 604800), maxSlippageBps (5 to 300, default 50). Cancel: action:"cancel", orderId (ord_ + 32 hex).

LegFields
limit_sell, limit_buy, take_profitprice: USDC per coin, up to 6 decimals, 1 to 10000000
stop_lossprice, worstBps (9000 to 10000)
trailing_stopprice, trailBps (200 to 5000), worstBps
dcaside (buy or sell), everySeconds (300 to 604800), slices (2 to 48). No price; leave out expiresInSeconds.

At most 5 open orders per connection and 10 per owner. Smallest order 1 USDC worth. A trigger must sit at least 0.2% from the market. A repeat order runs at most 30 days in all and is one order on its own. Stops need two consecutive checks. The owner's balance is never shown; a low balance is refused by reason only. An agent cannot cancel an order that already has a swap waiting; the owner cancels it in Trade.

States: draft, watching, triggered, card_ready, filled, needs_attention, paused, cancelled, expired. Final: filled, cancelled, expired. Track with odei_wallet_read {kind:"orders"}; once triggered, cardOperationId is the operation to track.

Refusals, with compact_wallet_ prefix: order_off, order_paused, order_agent_limit, order_order_limit, order_balance_low, order_pending, order_request_conflict, order_not_yours, order_card_open, order_changed, order_unavailable, orders_unread, order_chain_unsupported, order_pair_unsupported, order_amount_invalid, order_expiry_invalid, order_slippage_invalid, order_legs_invalid, order_price_invalid, order_side_invalid, order_schedule_invalid, order_kind_unsupported, order_request_invalid.

The paramsSchema for odei-order is behind the server. The server validates with its own code, so send chainId, coin and dca legs as written here.

Bridges

cctp-bridge destinations are 1, 10, 137, 8453, 42161, 43114. finality is standard (default; about 15 to 20 minutes from L2s, no protocol fee) or fast (soft finality in seconds, with a protocol fee, not offered from every chain). Omit maxFeeAtomic and ODEI fills it from a live Circle quote.

best-bridge destinations are 1, 10, 56, 137, 4663, 8453, 42161. BNB Chain and Polygon destinations vary by a runtime switch; read paramsSchema. token is USDC (default) or ETH, and ETH moves in steps of 0.000001 ETH. provider and expectedProvider take cctp-fast, cctp-standard, across, stargate, debridge, relay or cctp. expectedMinOutAtomic is a string minimum. recipient defaults to the owner wallet.

relay-topup legs are {destinationChainId: 56|137|4663, amountAtomic}, up to 3, distinct. A refund is Relay's action. Raw calls to Relay's depository are refused.

Lending, yield and hedges

aave-supply-withdraw and spark-supply-withdraw take action supply or withdraw and accept max on withdraw. yield-withdraw providerId: aave-v3, compound-v3, fluid-lending, morpho-vaults, morpho-vaults-2, morpho-vaults-3, morpho-v2-1, morpho-v2-2, spark-savings, moonwell, ethena-susde. best-yield optional holdDays 1 to 365, default 30; maxTier T1 or T2, default T2. aave-hedge ratioBps is 5000 or 9800; aave-hedge-adjust targetRatioBps is 5000, 8000 or 9800. asset is WETH by default, cbBTC on Base, WBTC on Arbitrum. These recipes are tools, and nothing on this page is financial advice.

Review links

On awaiting_owner give the owner reviewUrl unchanged, normally by relaying ownerMessage verbatim. The owner sees decoded calls, the simulation and the network fee and approves in ODEI, not in chat. The link carries account parameters; return it with all of them.

  • A prepared review lasts at most 5 minutes. Opening the link re-prepares it. validity.expiresAt is the real limit on approval.
  • reviewUrl is null when the operation is final (except a reverted operation with a retry available), expired or blocked.
  • On a continued operation never give the old link. Follow continuedBy.
  • On an operation Auto ran before it went off (owner_signing or broadcast with autoDecision.decision ran), give no reviewUrl and do not propose again.

odei_wallet_status

Pass exactly one of operationId (meop_ + 32 hex, plus revision?) or proposalId (mesp_ + 32 hex). Optional: refresh:true (calls only: re-reads receipt and finality from chain and records evidence, never signs or sends), detail (compact or full, calls only), waitSeconds (0 to 20, operationId only).

odei_wallet_status {"operationId":"meop_<32 hex>","waitSeconds":20}

waitSeconds holds the call and answers on the first change of state or once final, with waited{seconds, changed}. Call again at once until final:true. Without it wait retryAfterMs: about 15 s awaiting owner, 10 to 15 s while an operation is sending or confirming, 60 s for minutes-scale or unknown, null when there is nothing to poll. Finality usually follows inclusion by about 10 s on Base and OP, about 36 s on Ethereum.

The result has outcome, final, status{key, label}, transactionHash, receipt, fees, nextAction, retryAfterMs, autoDecision. A final result is compact unless detail:"full", which adds traces, historical receipt, provenance, preparations and, for a confirmed best-swap, fillReport. Errors: compact_wallet_selector_required, compact_wallet_operation_id_invalid, compact_wallet_proposal_id_invalid, compact_wallet_invalid_request.

Outcomes

Relay status.label and follow nextAction. Prepared, sent and executed differ. Only confirmed may be reported as executed.

outcomeFinalMeaning
awaiting_ownernoReady for the owner
owner_signingnoSigning in progress
broadcastnoSent, confirming
included_not_finalnoIn a block, not final
confirmedyes, when all steps confirmExecuted
revertedyes, but can stay not final; status says soFailed on chain
cancelledyesCancelled
replacedyesAnother operation settled the nonce
expiredyesPast its window
continuedyescontinuedBy carries the remaining steps
reorgedyes, once ODEI resolved itNever resend
unknownnoUnresolved, not failed

Inclusion is not a verified financial result. financialOutcome reads unverified_unless_evidence_present. Amounts come from evidence; otherwise say unverified. A sequential operation confirms only when every step confirms, and a final step shows awaiting_owner for the next.

Typed data: signatureState is awaiting_owner, claimed, signing, released, cancelled, expired or unknown. signatureWithheld is never_returned, odei_posts_to_cow or owner_only. CoW order outcomes: open, partially_filled, filled, expired, cancelled, withdrawn, rejected, signed_not_posted_by_odei. A CoW order state is the orderbook's report. A fill is success only once effects are verified on chain.

Bridge delivery

For a bridge, confirmed means the source transaction is final, not that funds arrived. Status adds bridgeDelivery with a stage and summary, deliveryFinal and delivered. It is done when delivery is final or a refund is proven. manualCompletion offers cctp-receive, and the delivery read offers debridge-cancel for an unfilled order. A refund on the way: tell the owner, do not poll.

odei_wallet_cancel

Only when the owner asks. One selector:

SelectorEffect
operationId (+ revision)Cancel one unsigned call operation
state: unsigned, expired or all-unsigned, plus chainId?, olderThanMinutes? (0 to 525600), limit? (1 to 100, default 50), preview?Filters preview by default
operations [{operationId, revision}] (1 to 100)From confirm.operations
proposalIdUnsigned typed data gets ownerCancelUrl and state owner_action_required, whatever the scopes. Only a signed, placed CoW order goes to the off-chain cancel signature.

A filter call previews: report would_cancel, then call again with operations: confirm.operations (or preview:false). unsigned means never opened for signing, and includes expired. all-unsigned also covers owner-opened unsigned operations.

Without capital.propose, filters and preview refuse, and one operationId or proposalId returns ownerCancelUrl and state owner_action_required.

Result: {kind, preview, selector, results, counts, complete, hasMore, confirm?, message}. Done only when complete:true. hasMore:true means more match. Per-item states: cancelled, already_cancelled, not_cancellable, would_cancel, not_found, not_saved (concurrent change; repeat the same call). signaturesRevoked is always false. CoW states: cancellation_awaiting_owner, cancellation_signed, cancellation_unavailable, not_cancellable, owner_action_required.

Errors: compact_wallet_selector_required, compact_wallet_state_required, compact_wallet_cancel_operations_invalid, compact_wallet_scope_required (403), compact_wallet_invalid_request.

Safety refusals

Refused before anything is saved. A same-requestId retry is judged again.

  • Unlimited approve, increaseAllowance, setApprovalForAll or Permit2 allowance to a spender that is not a known protocol contract.
  • Token access to a plain wallet that has no code.
  • Any address on a public scam list.
  • Non-standard approval calldata.
  • Making an address an Aave position manager.
  • Credit delegation to unverified delegatees.
  • Delegatecall and uninspectable wallet envelopes.
  • Calls to the wallet itself or its modules.
  • Retired routers.

Approve exactly the amount the next call spends, inside the same atomic batch, and reset to 0. Recipes do this. Pinned bridge contracts accept only Across depositV3 and swapAndBridge, Stargate send and deBridge createOrder.

Codes: compact_wallet_unbounded_approval_refused (hint exact_amount_in_same_atomic_batch, canonical_abi_encoding, stop_and_tell_owner, known_delegatee_only or direct_calls), compact_wallet_eoa_spender_refused, compact_wallet_flagged_address_refused (hint stop_and_tell_owner: stop, tell the owner, do not retry or route around), compact_wallet_owner_only_call_refused, compact_wallet_retired_router_refused, compact_wallet_spender_check_limited, compact_wallet_spender_check_unavailable, compact_wallet_relay_raw_deposit, compact_wallet_typed_data_unsupported. Risks that are not refused appear as riskFlags.

Blocked reasons

After saving, preparation may stop. Follow message. A blocked result carries cancel{tool:"odei_wallet_cancel", arguments}. Contract revert text is quoted as untrusted data.

ReasonNote
simulation_failederror.diagnosis names the call
balance_insufficientfundingShortfall gives the exact native amount. After funding retry the same requestId.
block_gas_limit_exceeded, gas_limit_insufficient, gas_limit_invalidFix the gas settings
total_fee_unbounded, total_fee_limit_exceededFee limits
prepare_failed, sequence_window_shortFix the cause

Except balance_insufficient, fix the cause and propose with a NEW requestId.