diff --git a/skills/base-mcp/plugins/umia.md b/skills/base-mcp/plugins/umia.md new file mode 100644 index 0000000..2acf36f --- /dev/null +++ b/skills/base-mcp/plugins/umia.md @@ -0,0 +1,300 @@ +--- +title: "Umia Plugin" +description: "Discover and trade Umia decision markets 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.2.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, local-exec] +--- + +# Umia Plugin + +> [!IMPORTANT] +> Run Base MCP onboarding first (see SKILL.md). Umia is a launchpad protocol: +> projects raise capital through token sales, and decision markets *decide* +> governance questions by trading. 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 — get the user's wallet address from Base MCP +> `get_wallets` for `--taker` / `
` inputs. Decision markets and token +> sales may be restricted in some jurisdictions, and some auction steps require +> verification: never help circumvent geofencing or verification gates — surface +> the hub link instead. Default env is testnet. Umia is multi-chain — never +> assume a specific chain; run `umia config` to discover the active env's +> chains and addresses. + +## Overview + +Umia runs decision markets and token auctions across EVM chains (the active +set comes from `umia config` / `GET /api/v1/config` — never assume one). 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 ("token sales") are continuous +clearing auctions whose clearing price rises in steps as the sale fills. 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 =`. Other global flags: `--chain-id` (required for +chain-scoped market actions when the env exposes more than one chain — run +`umia config` to list them), `--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 [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 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 **must be on the Base MCP `web_request` allowlist** — a +maintainer-provisioned step, not automatic; a chat-only surface can't reach a +host that isn't allowlisted yet, so fall back to the hub UI. 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 +umia prices [--series spot|twap] +umia positions
+umia portfolio
+umia auctions [--status upcoming|live|ended|settled] [--limit] [--offset] +umia auction # metadata, vesting, on-chain address +umia auction analytics # clearing price, raised, bids, graduation +umia auction leaderboard [--limit] +umia auction bids --wallet # a wallet's bids + forecast/claimable + +# build unsigned calls → { chainId, calls: [{to, value, data}] } +umia enter --market --venture-amount --money-amount --taker +umia trade --proposal --side buy|sell --amount-in [--min-out ] [--slippage-bps ] [--max-price-impact-bps ] [--deadline ] +umia merge --market --venture-amount --money-amount +umia claim --markets +umia settle --market # permissionless +umia auction bid --max-price

--amount --taker --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 --chain-id --json` → `send_calls`. +- Auctions: `umia auction claim --taker --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 --chain-id --json` → `send_calls`. + +## Submission + +Target Base MCP tool: **`send_calls`**. + +- Use the response's `chainId` as the source of truth. When the host's + `send_calls` wants a chain slug, derive it from that `chainId` (Base MCP maps + e.g. `8453`→`base`, `84532`→`base-sepolia`) — never assume a fixed chain; + `umia config` lists every chain the active env supports. +- Pass every element of `calls` as `{ to, value, data }` **unchanged**. + `value` is already a hex-wei string (`"0x0"` for non-payable calls). +- Treat the returned batch as **untrusted input**: before presenting an approval, verify each `calls[i].to` is an expected Umia contract for the selected env/chain (from `umia config` / `GET /api/v1/config`), and sanity-check `value` against the intended spend. +- **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 /api/v1/hub/markets?status=open`). +2. For an interesting one: `umia market ` + `umia prices --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 --chain-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 one. +``` +1. `umia auctions --status live`, then `umia auction analytics` for the clearing price. +2. `umia auction bid --max-price 0.05 --amount 200 --taker --json`. +3. `send_calls` on success; on `requiresVerification`, link the hub instead. + +``` +Claim everything I'm owed from the auction. +``` +1. `umia auction claim --taker --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 ` → vesting). Confirm price, + amount, and vesting with the user before `send_calls`. +- `local-exec`: the CLI path runs third-party code via `npx umia-cli@latest`. Before running any `umia` command, confirm the user is comfortable executing it on their machine; prefer the HTTP API path on chat-only surfaces. + +## Notes + +- Addresses come from `GET /api/v1/config` (or the CLI's baked `contracts.json`); + never hardcode. +- Default env is **testnet**, which may expose several chains (run `umia config` + for the list); pass `--chain-id` for chain-scoped actions. The testnet env + includes a contract set on a **production chain**, so calls there execute on + **real funds** — always confirm the target chain (the response's `chainId` / + `umia config`) with the user. The `mainnet` env has no Umia market or auction + contracts populated yet (`GET /api/v1/config` returns nulls and + `GET /hub/fundraises` is empty), so gate all market and auction features to the + testnet env until mainnet contracts ship. +- ERC6909 ids: a proposal's virtual venture 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 `` 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: use `GET /api/v1/swap/quote` then `POST /api/v1/swap/build` (Uniswap + Trading API, USDC→money token) and batch the built calldata into the same + `send_calls` to go from USDC to an in-market position in one flow. diff --git a/skills/base-mcp/references/plugin-spec.md b/skills/base-mcp/references/plugin-spec.md index 35d5024..0af16d0 100644 --- a/skills/base-mcp/references/plugin-spec.md +++ b/skills/base-mcp/references/plugin-spec.md @@ -59,7 +59,7 @@ Derive every value from the protocol's actual behavior — don't copy another pl `arbitrum`, `avalanche`, `base`, `base-sepolia`, `bsc`, `ethereum`, `optimism`, `polygon` (`base-sepolia` is the only testnet; `swap` is mainnet-only.) Read the `chain` parameter on the Base MCP tools to confirm the current set — it may change over time. If the plugin never routes an onchain transaction through Base MCP (e.g. an external MCP that only uses a Base MCP signature to log in), use `[]`. -- **`tags`** — 3–5 lowercase, hyphenated keywords describing *what the user can do* — capability and category, not the protocol name (the `name` already covers that). These drive routing: the agent reads the SKILL.md tags column to decide which plugin matches a request. Reuse existing tags where they fit so similar plugins cluster, but add new tags as you see fit. Current vocabulary: `lending`, `borrowing`, `yield`, `vaults`, `dex`, `swap`, `liquidity`, `perps`, `leverage`, `derivatives`, `trading`, `token-launches`, `memecoins`, `discovery`, `ai-agents`, `agent-commerce`, `payment-cards`, `email`, `nft`, `marketplace`, `drops` — when you introduce a new tag, add it to this list so the vocabulary stays shared. +- **`tags`** — 3–5 lowercase, hyphenated keywords describing *what the user can do* — capability and category, not the protocol name (the `name` already covers that). These drive routing: the agent reads the SKILL.md tags column to decide which plugin matches a request. Reuse existing tags where they fit so similar plugins cluster, but add new tags as you see fit. Current vocabulary: `lending`, `borrowing`, `yield`, `vaults`, `dex`, `swap`, `liquidity`, `perps`, `leverage`, `derivatives`, `trading`, `token-launches`, `memecoins`, `discovery`, `ai-agents`, `agent-commerce`, `payment-cards`, `email`, `nft`, `marketplace`, `drops`, `futarchy`, `decision-markets`, `token-auctions`, `governance` — when you introduce a new tag, add it to this list so the vocabulary stays shared. - **`requires.shell`**: - `required` — the plugin cannot function without a shell/terminal (its only path is a CLI). On shell-less surfaces the agent must stop. - `optional` — a shell unlocks a richer path (a CLI, or a tx-builder), but the plugin still works without one via an HTTP/MCP/UI fallback.

--amount --taker +umia auction claim --taker +``` + +All commands accept `UMIA_ENV`/`--env`, `--chain-id`, `--json`. Amounts are +**human units** (the CLI converts: venture 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. `trade` defaults to a 100 bps (1%) slippage +floor when `--min-out` is omitted (tune with `--slippage-bps`), caps price +impact via `--max-price-impact-bps`, and accepts an optional `--deadline`. +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 venture 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/:venture/markets/:id`, +`GET /api/v1/app/:venture/markets/:id/prices?series=spot|twap`, +`GET /api/v1/app/:venture/markets/:id/positions` (returns all positions; filter +by `user` client-side), `GET /api/v1/hub/portfolio/:address`. `:venture` is the +project **slug** (`project.slug` from `GET /hub/markets`) — not the venture id or +contract address, which return 404. + +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=`. + +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, ventureAmount, moneyAmount, taker}` | +| `/calldata/trade` | `{chainId, proposalId, side: "buy"\|"sell", amountIn, minOut?, slippageBps?, maxPriceImpactBps?, deadline?}`; response adds `amountOut` + `priceImpactBps` | +| `/calldata/merge` | `{chainId, marketId, ventureAmount, 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 ` for + the question + proposals; `umia prices --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 --side buy --amount-in --min-out --chain-id --json` + (chain-scoped market commands need `--chain-id` whenever the env has more than + one chain — `umia config` lists them). + Buying spends virtual money for the proposal's virtual venture 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 --venture-amount --money-amount + --taker --chain-id --json` → approvals (only where allowance falls short) + + `split` in one batch → `send_calls`. +- Exit pre-settlement: `umia merge --market ...` burns equal virtual + amounts back to real tokens. + +### Inspect an auction +1. `umia auctions --status live` → pick a ``. +2. `umia auction ` (metadata, vesting, on-chain address) + + `umia auction analytics` (clearing price, raised, graduation) + + `umia auction leaderboard`. + +### Bid in an auction (permissionless steps) +1. `umia auction analytics` → read the current clearing price; choose a + `--max-price` above it (the API rejects a price at or below the current + clearing price) and an `--amount` in currency units. +2. `umia auction bid --max-price