Verify what your agent traded on Coinbase.
Coinbase for Agents gives an agent a wallet, a portfolio and an MCP server to trade with. Coinbase's controls run before the order: the portfolio the agent is scoped to, the permissions on its key, the cap on what it may spend. CommitLayer runs after it. It reads Coinbase's own record of the order and says whether the trade the agent reported is the trade that happened.
Read-only, through a CDP key with the View permission and nothing else. CommitLayer never places, cancels or approves an order.
What goes wrong, and what the transcript shows
Each of these leaves the agent's own account of the trade looking correct. The verdict comes from Coinbase's record, under a contract, never from the tool's answer.
Drafted, never executed
The agent composes the order, the chat shows it, and the call that would place it never happens or is rejected. The transcript reads like a trade. Coinbase has no order.
expected_effect_missing
The wrong product
Told to buy ETH-USD, the agent picks ETH-USDC. The order is real and filled, on a product nobody asked for. The intended product shows nothing; the other shows an effect with no action behind it.
expected_effect_missing + orphan effect
Placed, not filled
The order is accepted and rests open. The agent reports the trade done because the tool said OK. An accepted order is not a filled one.
expected_effect_missing: order_filled
Executed twice
A timeout after the first order went through, then a retry without an idempotency key. The agent reports one trade; Coinbase holds two.
duplicate_effect
The amount off by a unit
Asked for 50, the agent sends 500. Every step succeeded. The order's notional is compared with the amount the action recorded, not with what the agent says it sent.
effect_attr_mismatch: quote_value
Busted afterwards
The trade settles as PASS. Days later Coinbase reverses or corrects the fill. The reversal in the fills list re-verifies the action to FAIL and names the fill.
reversed: order_reversed
The first two are the ones Coinbase's own documentation for the MCP server warns about: hosted chat clients that draft an order and stop short of executing it, and smaller models that pick the wrong product. Coinbase MCP documentation
The contract
One action contract, coinbase_agent_trade, in the library. The subject is the product the agent was told to trade; the limits are template values to replace with your own.
What must hold
- Only BUY or SELL, and at most the per-order notional.
- At most the agent's notional total across 24 hours, summed over every order it created, not only this one.
- Exactly one order on the product asked, created within the window and filled, for the amount asked.
- No order on that product that was cancelled, expired or rejected.
- No fill busted or corrected by Coinbase within 7 days. One that is re-verifies the settled action to FAIL.
- UNKNOWN, not PASS, when Coinbase is not connected or the record has not arrived yet.
What the connector reads
Orders and fills from the Advanced Trade API, seven days back on every sync, scoped to the agent's portfolio when you name it. Product, side, notional, status, fill price and time, and any fill later reversed or corrected. Never balances, deposits, withdrawals, payment methods or personal details. The key cannot trade or transfer; the connector would refuse one that could do more than view.
Every fact is keyed on the product id Coinbase uses, so the action your agent records and the evidence Coinbase supplies name the same thing without any mapping.
coinbase_agent_tradeHow it is wired
Three steps. None of them changes what the agent decides.
1. Connect Coinbase
In the workspace, add the Coinbase connector with a CDP API key created with the View permission only, ECDSA, restricted to the portfolio the agent trades in. The key is stored encrypted and signs two-minute read tokens; nothing else.
2. Record the order
Put the MCP recorder in front of the Coinbase MCP server and map
orders_createto the contract; the order is recorded as an action before the call is forwarded. Or record it with one API call from your own runtime.3. Read the verdict
Provisional at once, settled when the window closes, re-checked when a reversal arrives. PASS, FAIL or UNKNOWN per lens, with the reason and the Coinbase records behind it, hashed and chained.
Recorder mapping for the Coinbase MCP server
{
"agent_id": "trading-agent",
"tools": {
"orders_create": {
"contract_id": "coinbase_agent_trade",
"action_type": "place_order",
"subject": "arguments.product_id",
"subject_kind": "product",
"params": { "amount": "arguments.quote_size", "side": "arguments.side" },
"action_id": "trade:{arguments.client_order_id}"
}
}
}The paths follow the create-order request (product id, side, quote size). Run the recorder once with --warn-unmapped against the server's own tool list and adjust them if the argument names differ. The Coinbase server is remote; the recorder is a stdio proxy, so put it in front of the stdio bridge your client uses to reach it.
Or one API call
POST /v1/actions
{
"contract_id": "coinbase_agent_trade",
"action_type": "place_order",
"subject_id": "TSLA-USD",
"subject_kind": "product",
"agent_id": "trading-agent",
"params": { "amount": 50, "side": "BUY" }
}Recorded with a recorder key, which can record actions and read verdicts and do nothing else. The key that supplies the evidence is a different one.
Try it without an account
The Failure Lab replays a scripted agent placing a trade on a sandbox broker through a chaos layer, then asks the production engine for the verdict. Six failure modes, the trace on the left, the systems of record on the right.
What this is not
- It does not stop, approve or size an order. Coinbase's own controls do that before the trade. CommitLayer produces the evidence afterwards, on every plan.
- It is not trading advice and says nothing about whether a trade was a good one. It says whether the trade that happened is the trade that was asked for and reported.
- CommitLayer is not affiliated with Coinbase and takes nothing from it. Coinbase, Coinbase for Agents and the Coinbase mark belong to Coinbase and appear here only to name the system the connector reads.
- Known limits: the side is limited on the action and shown in the evidence but not compared with the order; a product the account has never traded answers UNKNOWN rather than FAIL until a record of it exists; the connector has been tested against recorded responses in the shape of Coinbase's reference, not yet against a live account.