---
title: "Umia Plugin"
description: "Discover and trade Umia decision markets (futarchy) and bid in token auctions via the umia-cli or HTTP API; builds unsigned calldata routed through send_calls."
tags: [futarchy, decision-markets, token-auctions, governance, trading]
name: umia
version: 0.1.0
integration: hybrid
chains: [base, base-sepolia]
requires:
  shell: optional
  allowlist: ["api.testnet.umia.finance", "api.mainnet.umia.finance"]
  externalMcp: null
  cliPackage: "npx umia-cli@latest"
auth: none
risk: [slippage, low-liquidity, irreversible]
---

# Umia Plugin

> [!IMPORTANT]
> Run Base MCP onboarding first (see SKILL.md). Umia is a futarchy protocol:
> markets *decide* a governance question by trading, and projects raise via
> continuous clearing auctions. This plugin only reads data and builds unsigned
> calls. It never signs or broadcasts outside Base MCP. Never ask for or use a
> private key. Default env is testnet (`base-sepolia`); mainnet currently hosts
> auctions only, no futarchy markets.

## Overview

Umia runs decision markets and token auctions on Base. Each market poses a
governance question with 2+ proposals (conditional CPMM pools of ERC6909
virtual tokens); the highest-TWAP proposal above threshold wins and converts
1:1 to real tokens at settlement. Auctions ("fundraises") are continuous
clearing auctions with a single clearing price. The plugin reads
markets/auctions/prices/positions over HTTP and builds **unsigned**
`{ to, value, data }` calldata via the auth-free `/api/v1/calldata/*`
endpoints, then routes every write through Base MCP `send_calls`. With a shell
it uses the `umia` CLI (`npx umia-cli@latest`); on chat-only surfaces it calls
the same HTTP API directly. The CLI is a thin client over that API: it only
*prepares* calls, never executes them.

## Installation

Runs via npx, no global install:

```
npx umia-cli@latest --version
```

Select the environment with `UMIA_ENV=testnet|mainnet` (default `testnet`) or
`--env`. Contract addresses are baked in from the protocol's `contracts.json`
and also served by `GET /api/v1/config`; override any with
`--contract <name>=<addr>`. Other global flags: `--chain-id` (required for
chain-scoped market actions on multi-chain envs; testnet has `84532` and
`8453`), `--api-base`, `--json` (machine-readable, always use it when piping
to `send_calls`).

## Surface Routing

| Capability | Harness HTTP / `web_request` | CLI (shell available) | Fallback |
|---|---|---|---|
| Read markets/prices/positions/portfolio | `GET {API}/api/v1/...` | `umia markets/market/prices/positions/portfolio` | Umia hub UI link |
| Read auctions/analytics/leaderboard/bids | `GET {API}/api/v1/hub/fundraises...` | `umia auctions`, `umia auction <slug> [analytics\|leaderboard\|bids]` | hub UI link |
| Build market enter/trade/merge/claim/settle | `POST {API}/api/v1/calldata/*` | `umia enter\|trade\|merge\|claim\|settle` | hub UI link |
| Build auction bid/claim | `POST {API}/api/v1/calldata/auction-{bid,claim}` | `umia auction <slug> bid\|claim` | hub UI link (also where verification-gated bids go) |
| Submit | `send_calls` | `send_calls` | n/a |

Routing: **shell available →** prefer the `umia` CLI (it converts human
amounts to wei and snaps bid prices to the tick grid). **Chat-only /
no shell →** use the harness HTTP tool or `web_request` against the endpoints
below. Both API hosts are on the allowlist; amounts must then be raw wei
strings (see `## Endpoints`). **Neither works →** link the Umia hub UI.
`{API}` is `https://api.testnet.umia.finance` for testnet,
`https://api.mainnet.umia.finance` for mainnet.

## Commands

```
# reads
umia config
umia markets [--status open|pending|ended|settled|completed]
umia market <qorg> <id>
umia prices <qorg> <id> [--series spot|twap]
umia positions <qorg> <id> <address>
umia portfolio <address>
umia auctions [--status upcoming|live|ended|settled] [--limit] [--offset]
umia auction <slug>                       # metadata, vesting, on-chain address
umia auction <slug> analytics             # clearing price, raised, bids, graduation
umia auction <slug> leaderboard [--limit]
umia auction <slug> bids --wallet <addr>  # a wallet's bids + forecast/claimable

# build unsigned calls → { chainId, calls: [{to, value, data}] }
umia enter  --market <id> --qorg-amount <a> --money-amount <b> --taker <addr>
umia trade  --proposal <id> --side buy|sell --amount-in <a> [--min-out <m>]
umia merge  --market <id> --qorg-amount <a> --money-amount <b>
umia claim  --markets <id,id,...>
umia settle --market <id>                 # permissionless
umia auction <slug> bid   --max-price <p> --amount <a> --taker <addr>
umia auction <slug> claim --taker <addr>
```

All commands accept `UMIA_ENV`/`--env`, `--chain-id`, `--json`. Amounts are
**human units** (the CLI converts: qOrg tokens 18 decimals, money via the
chain's USDC decimals, auction bids via the auction's currency decimals) and
every conversion is echoed as human + wei. `--max-price` is currency-per-token
and is snapped **down** to the auction's tick grid; pass `--max-price-x96` to
supply a raw tick price instead. Action commands print
`{ chainId, calls: [...] }`; if an auction step requires verification,
`auction bid` prints the reason + hub link, emits no calls, and exits 1.
`enter` takes no qorg slug (the token pair resolves on-chain from the market
id) and only `enter` and the auction commands take `--taker`; the other
actions are `msg.sender`-scoped.

## Endpoints

Read (markets): `GET /api/v1/config`, `GET /api/v1/hub/markets`,
`GET /api/v1/app/:qorg/markets/:id`,
`GET /api/v1/app/:qorg/markets/:id/prices?series=spot|twap`,
`GET /api/v1/app/:qorg/markets/:id/positions` (returns all positions; filter
by `user` client-side), `GET /api/v1/hub/portfolio/:address`.

Read (auctions): `GET /api/v1/hub/fundraises[?status=upcoming|live|ended|settled]`,
`GET /api/v1/hub/fundraises/:slug` (analytics live under `fundraise.auction`;
may be absent until indexed), `GET /api/v1/hub/fundraises/:slug/leaderboard`,
`GET /api/v1/hub/fundraises/:slug/bids?walletAddress=<lowercase>`.

Build: all auth-free `POST /api/v1/calldata/*`, JSON bodies, amounts as
**decimal-wei strings**, responses `{ chainId, calls: [{to, value, data}] }`
with `value` a hex-wei string and approvals ordered first (de-duped against
live allowances):

| Endpoint | Body |
|---|---|
| `/calldata/enter` | `{chainId, marketId, qOrgAmount, moneyAmount, taker}` |
| `/calldata/trade` | `{chainId, proposalId, side: "buy"\|"sell", amountIn, minOut?, maxPriceImpactBps?, deadline?}`; response adds `amountOut` + `priceImpactBps` |
| `/calldata/merge` | `{chainId, marketId, qOrgAmount, moneyAmount}` |
| `/calldata/claim` | `{chainId, marketIds: [..]}` |
| `/calldata/settle` | `{chainId, marketId}` |
| `/calldata/auction-bid` | `{slug \| auctionAddress+chainId, maxPrice, amount, taker}`; `maxPrice` is a raw X96 tick price aligned to the tick grid; gated steps return `{requiresVerification, reason, hubUrl}` with no calls |
| `/calldata/auction-claim` | `{slug \| auctionAddress+chainId, taker}`; may return `calls: []` plus a `note`, and `claimable: {bidIds, claimBlock, blocksRemaining}` before the claim window opens |

Auction claims compose **exit calls first, then one `claimTokensBatch`**: the
exits also refund unspent bid currency, so a single claim batch handles
refunds and token transfers together. Do not promise or attempt a separate
refund step.

## Orchestration

### Discover & analyze a market
1. `umia config` (or `GET /config`) to learn chains and addresses.
2. `umia markets --status open` → pick a market; `umia market <qorg> <id>` for
   the question + proposals; `umia prices <qorg> <id> --series twap` for the
   implied winner (settlement is by TWAP above threshold).

### Trade a conviction
1. Resolve the `proposalId` from the market detail.
2. `umia trade --proposal <id> --side buy --amount-in <a> --min-out <m> --chain-id <id> --json`
   (chain-scoped market commands need `--chain-id`; the testnet env has two chains).
   Buying spends virtual money for the proposal's virtual qOrg token; **no
   approval call is needed** (entering via `split` grants a standing virtual
   allowance). A trade is always a single call.
3. Check `priceImpactBps` (warn the user above ~100 bps) and confirm
   `--min-out` was set, then pass `calls` to `send_calls`.

### Enter / exit market positions
- Enter: `umia enter --market <id> --qorg-amount <a> --money-amount <b>
  --taker <wallet> --chain-id <id> --json` → approvals (only where allowance falls short) +
  `split` in one batch → `send_calls`.
- Exit pre-settlement: `umia merge --market <id> ...` burns equal virtual
  amounts back to real tokens.

### Inspect an auction
1. `umia auctions --status live` → pick a `<slug>`.
2. `umia auction <slug>` (metadata, vesting, on-chain address) +
   `umia auction <slug> analytics` (clearing price, raised, graduation) +
   `umia auction <slug> leaderboard`.

### Bid in an auction (permissionless steps)
1. `umia auction <slug> analytics` → read the current clearing price; choose a
   `--max-price` at/above it and an `--amount` in currency units.
2. `umia auction <slug> bid --max-price <p> --amount <a> --taker <wallet> --json`.
   The CLI snaps the price down to the tick grid and echoes the effective
   price; the API computes the tick-insertion hint and de-dupes the
   currency→Permit2→auction approval chain.
3. If it returns `calls` → `send_calls`. If it exits 1 with
   `requiresVerification` → tell the user this auction step needs verification
   and link the `hubUrl`; do not retry or work around it.

### Claim market winnings / auction tokens
- Markets (after settlement): `umia claim --markets <ids> --chain-id <id> --json` → `send_calls`.
- Auctions: `umia auction <slug> claim --taker <wallet> --json`. Before the
  claim block it returns exit calls only plus `claimable` metadata. Submit
  the exits now (they refund unspent currency) and rebuild after
  `claimBlock`; afterwards the batch ends with `claimTokensBatch`.

### Settle an ended market (permissionless)
`umia markets --status ended` → `umia settle --market <id> --chain-id <id> --json` → `send_calls`.

## Submission

Target Base MCP tool: **`send_calls`**.

- Map the response's `chainId` to the chain string: `8453` → `base`,
  `84532` → `base-sepolia`.
- Pass every element of `calls` as `{ to, value, data }` **unchanged**.
  `value` is already a hex-wei string (`"0x0"` for non-payable calls).
- **Preserve array order**: approvals precede the action and auction-claim
  exits precede the batch claim; the builder ordered them deliberately.
- Never modify `data`, never add a signer, never broadcast outside Base MCP.
- If a builder returns `requiresVerification` instead of `calls`, do not
  attempt the bid. Surface the `hubUrl`. If `auction-claim` returns
  `calls: []`, relay its `note` (nothing to do, or the claim window hasn't
  opened).

## Example Prompts

```
What Umia decision markets are open right now?
```
1. `umia markets --status open` (or `GET /hub/markets?status=open`).
2. For an interesting one: `umia market <qorg> <id>` + `umia prices <qorg> <id> --series twap`.

```
I think proposal 14 is right — buy 50 USDC of it.
```
1. `umia trade --proposal 14 --side buy --amount-in 50 --min-out <m> --chain-id <id> --json`.
2. Report `priceImpactBps` and the expected out; on approval, `send_calls` with the returned batch.

```
Show me live Umia token auctions and bid 200 USDC at 0.05 in the <project> one.
```
1. `umia auctions --status live`, then `umia auction <slug> analytics` for the clearing price.
2. `umia auction <slug> bid --max-price 0.05 --amount 200 --taker <wallet> --json`.
3. `send_calls` on success; on `requiresVerification`, link the hub instead.

```
Claim everything I'm owed from the <project> auction.
```
1. `umia auction <slug> claim --taker <wallet> --json`.
2. Submit the returned batch; if `claimable` says the window hasn't opened, submit the exits now and tell the user when to come back (`claimBlock`).

## Risks & Warnings

- `slippage`: conditional CPMM pools re-price on every trade. Always pass
  `--min-out`, surface `priceImpactBps` before submitting, and never raise
  slippage tolerance silently.
- `low-liquidity`: proposal pools and fresh auctions can be thin; a market
  order into a thin pool moves the price materially. Check reserves
  (`umia market`) and `priceImpactBps` first.
- `irreversible`: settlement, claims, merges, and submitted bids cannot be
  undone. An auction bid below the final clearing price wins no tokens (the
  unspent currency is refunded at exit/claim); purchased tokens may be
  subject to vesting (`umia auction <slug>` → vesting). Confirm price,
  amount, and vesting with the user before `send_calls`.

## Notes

- Addresses come from `GET /api/v1/config` (or the CLI's baked `contracts.json`);
  never hardcode.
- Default env is **testnet**: full futarchy + auctions on `base-sepolia`
  (84532) and on Base **mainnet** (8453; the testnet *environment config*
  includes a contract set deployed on the mainnet chain, so calls there
  execute on real Base). The `mainnet` env currently has the auction factory
  only. Gate market features to the testnet env until its contracts ship.
- ERC6909 ids: a proposal's virtual qOrg token is `proposalId*2`, virtual
  money is `proposalId*2+1`; winners convert 1:1 at settlement.
- Bid prices are X96 fixed-point and must align to the auction's tick grid
  (`price % tickSpacing == 0`); the CLI handles conversion + snapping from a
  human price. Chat-only surfaces should compute
  `maxPrice = floor(human · 2^96 · 10^currencyDecimals / 10^tokenDecimals / tickSpacing) · tickSpacing`
  from the fundraise's `auction` data, or send the user to the hub.
- Auction `<slug>` is the project slug; live analytics require the auction to
  be on-chain and indexed; `fundraise.auction` may be absent for fresh
  deployments.
- The market `positions` endpoint returns all positions for the market;
  filter by `user` client-side (the CLI does).
- Funding: batch `GET /api/v1/swap/quote` (0x Permit2, USDC→money token) into
  the same `send_calls` to go from USDC to an in-market position in one flow.
