# vibe.market 2.1 — agent integration guide

This guide covers vibe.market 2.1, whose contract schema is
`vibemarket.shared-pot.v6`. The public app is
[`/vibemarket2`](https://vibechain.com/vibemarket2) and the human-readable
guide is [`/vibemarket2/docs`](https://vibechain.com/vibemarket2/docs).

vibe.market is experimental software. Pack-token prices can move, public pool
liquidity can be thin, exact rewards can temporarily wait for funding, and
tokens can lose all value. Never hold or request a user's private key.

## The safe rule

At the start of every session, read:

```text
GET https://vibechain.com/api/vibemarket2/runtime/versions
```

Select exactly one entry where:

- `schema` is `vibemarket.shared-pot.v6`;
- `retired` is not `true`;
- `chainId` is the chain the user expects; and
- `market`, `factory`, `pool`, `pot`, `entropy`, `weth`, and `poolManager` are
  present.

Do not select by array position, copy addresses from prose, or mix addresses
from two runtime entries. Before opening, require
`GET /api/vibemarket2/runtime/{runtimeId}/health` to return `ready: true`.

API data is a bounded projection, not an onchain receipt. Before every write,
read fresh state and quotes, preserve exact amounts as integers, simulate the
exact call from the user's account, show the user what will happen, and wait
for a successful receipt. Never retry an uncertain transaction blindly.

## HTTP API

Base URL:

```text
https://vibechain.com/api/vibemarket2/runtime/{runtimeId}
```

| Route | Purpose |
| --- | --- |
| `GET /health` | Projection and entropy-keeper readiness |
| `GET /markets?limit=50&before={cursor}` | Paginated packs |
| `GET /markets/{dropId}` | One pack, token, pool, odds, and totals |
| `GET /markets/batch?ids=1,2,3` | Up to 100 exact pack IDs |
| `GET /board?resource=quoteBuy&dropId={dropId}&packs={1..10}` | Buy quote in ETH |
| `GET /sealed?owner={wallet}` | Sealed-pack balances |
| `GET /claims?owner={wallet}` | Pending and revealed cash claims |
| `GET /nfts?owner={wallet}` | Collected card NFTs |
| `GET /holders?dropId={dropId}&limit=50` | Token holders |
| `GET /trades?dropId={dropId}&limit=50` | Pool trades |
| `GET /candles?dropId={dropId}&limit=50` | Price candles |
| `GET /pot` | Reward assets, protected claims, free capital, and shortfall |
| `GET /stream?topics=pot,market:{dropId},wallet:{wallet}` | SSE invalidations |

List routes return an opaque `next` cursor. Send it back as `before` without
modifying it until it is `null`. Re-read the relevant endpoint after an SSE
invalidation; the event is not the full state.

All projected onchain quantities are decimal strings. Keep Wei and 18-decimal
token units as `bigint`; do not convert exact values through JavaScript
`number`.

## How V2.1 works

Each creator launch makes a fixed-supply ERC-20 pack token, a card NFT
collection, and an ordinary hookless Uniswap V4 token/WETH pool. One pack is
`100000 × 10^18` token units.

A buy moves real WETH into that pack's public pool. A sealed pack can be held,
transferred, sold back, or opened. Opening sells exactly one token lot per pack
back into the same pool and locks the realized native ETH as opening principal.
Entropy chooses rarity, card definition, foil, and wear. Reveal creates the
exact fixed reward claim; it does not reserve a hypothetical jackpot before
rarity is known.

If an exact reward exceeds available reward-pot capital, the outcome and full
amount remain fixed. The claim reports a shortfall and cannot be sold or
collected until FIFO funding makes it whole. New openings pause while a known
shortfall exists. Never describe an underfunded claim as immediately cashable.

## Create a pack

The simplest supported path is the official Studio at
[`/vibemarket2/create`](https://vibechain.com/vibemarket2/create). It publishes
creator-signed metadata and then asks the creator's wallet to call the factory.

A same-origin UI may prepare hosted metadata with:

```text
POST /api/vibemarket2/runtime/{runtimeId}/prepare
Content-Type: multipart/form-data
```

Fields are `name`, `symbol`, `description`, `tiers`, `ethPerPack`, optional
`packArt`, repeated `tierArt`, and optional `cardsByRarity`. The response
contains `baseURI` and `createParams`. Preparation cannot launch a pool or
spend funds. It is same-origin protected; an external agent should use Studio
or provide its own durable HTTPS metadata rather than bypass that boundary.

For the canonical five-tier, approximately $2 launch, simulate and send this
wallet call to the discovered `factory`:

```text
createClassic(name, symbol, baseURI, ethUsdE8) -> dropId
```

`ethUsdE8` is the caller-supplied ETH/USD reference with eight decimals. It is
not an oracle. Require one successful `DropCreated` event from the expected
factory and decode its `dropId`, token, cards, and pool ID. If the receipt
succeeds but decoding fails, do not launch again; recover the receipt first.

## Buy and stash

1. Read the exact market and obtain a fresh buy quote for `count` from 1 to 10.
2. Use a short Unix-seconds deadline and a user-approved slippage ceiling.
3. Simulate this call to the discovered `market`:

```text
buySealed(dropId, count, maxEthIn, deadline)
value: maxEthIn
```

The contract refunds unused ETH. A sealed pack is an internal balance backed
by one token lot; it is not yet a revealed card.

## Buy and open atomically

Read `entropy.fee()` immediately before simulation, then call:

```text
buyAndOpen(dropId, count, maxEthIn, 0, deadline) -> pullId
value: maxEthIn + entropyFee
```

The fourth argument must be zero for V2.1. Require a successful `PackOpened`
receipt from the expected market. The transaction starts the pull; it does not
mean the rarity has already resolved.

## Open stashed packs

Quote the pool output for `count × 100000 × 10^18` token units, choose a
minimum opening-proceeds floor, read `entropy.fee()`, and call:

```text
openSealed(dropId, count, 0, minOpeningProceeds, deadline) -> pullId
value: entropyFee
```

Again, the third argument must be zero. If health is not ready or the
underwriter policy is disabled, stop. The user's sealed packs remain theirs.

## Sell or transfer stashed packs

For a sell, get a fresh pool quote and call:

```text
sellSealed(dropId, count, minProceeds, deadline, recipient) -> proceeds
```

For a transfer:

```text
transferSealed(dropId, recipient, count)
```

Require the expected market receipt before updating local state.

## Resolve and settle a card

The entropy keeper normally fulfills and resolves a pull. Once its entropy is
ready, anyone may call `resolve(pullId)`. Do not request a new random draw after
a failure; the pull's request is fixed.

For each revealed card, read:

```text
openingProceeds(cardId)
previewPayout(cardId, 0)
claimFunding(cardId) -> grossReward, fundedReward, shortfall, active
```

Only offer settlement when the claim is active and fully funded.

Cash out:

```text
sell(cardId, minSaleProceeds, minPayout, deadline, recipient) -> payout
```

Keep the NFT:

```text
collect(cardId, minSaleProceeds, minCreatorPayout, deadline, nftRecipient)
```

Sell pays the opener's fixed reward. Collect gives the opener the NFT, credits
90% of the reward to the pack creator, and leaves the 10% haircut in the shared
pot. Collect is available only before the pack's seven-day collection deadline
and the 300-collection limit. Sell remains available afterward.

## After every write

1. Require a successful receipt from the expected contract and chain.
2. Save the transaction hash and receipt block.
3. Poll `/health` until its indexed head is past the receipt block.
4. Re-read the exact market and affected wallet endpoints.
5. If indexing is delayed, report synchronization honestly. Do not repeat a
   confirmed financial action.

Stop on an unknown schema, retired runtime, wrong chain, missing address,
unready opening health, stale quote, failed simulation, unexpected event,
underfunded claim, or uncertain receipt.
