# Offer Safety Check

> Decode a Chia offer1... string, classify what's being traded on each side, fetch market prices, and surface a risk report before the user takes it. Use when the user pastes an offer they were sent, asks "is this offer fair?", or wants to vet a deal before opening their wallet. Accepts offer, max_unfavourable_pct as arguments for programmatic invocation.

- Skill: `spacetime-technology/offer-safety-check` (Agent Skill)
- Install (CLI): `npx skillmds@latest add spacetime-technology/offer-safety-check`
- Raw SKILL.md: https://api.skillmd.com/api/skills/spacetime-technology/offer-safety-check/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: Spacetime-Technology (https://skillmd.com/u/spacetime-technology)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/spacetime-technology/offer-safety-check

---


# Offer safety check

You are vetting a Chia offer string for the user before they take it. Decode it locally via chia-explorer, classify both sides, fetch market prices, and produce a clear "looks fine" / "looks off" / "outright bad" verdict. Read-only. No wallet, no signing — the user takes the offer in their own wallet if they want to.

This skill follows the conventions in this repo's `SKILLS.md`. Read that if anything below is unclear.

## Required capabilities

- **chia-explorer** (`mcp__chia-explorer__*`) — mandatory. The `decode_offer` and `decompile_puzzle` tools do the heavy lifting; offer decoding is local (no RPC).

## Resolve inputs

You need: `$offer`, `$max_unfavourable_pct`.

- `$offer` — the `offer1...` bech32m string. Required.
- `$max_unfavourable_pct` — how much worse than market you're willing to accept on the side you're giving up. Default `5` (5%). Set higher for less liquid CATs.

Resolve: arguments → context → ask user.

Strip whitespace from `$offer` (offers often get word-wrapped). If it doesn't start with `offer1`, emit `STATUS: failed`, `REASON: not an offer string`.

## Decode

Decode the offer locally. Extract:

- **Offered side** — what the *other* party is offering (what you'd receive).
- **Requested side** — what they want from you in return.

Each side is a list of assets:

- XCH amounts (mojos → XCH)
- CAT amounts, each with an `asset_id`
- NFT(s), each with a `launcher_id`

If decoding fails, emit `STATUS: failed`, `REASON: offer failed to decode`. Don't try to be heroic with a malformed string.

## Classify each asset

For every CAT, identify the asset. chia-explorer's decompile/classify tools return the asset_id. Match against the small set of well-known tickers (DBX, SBX, USDS, etc.). If unmatched, call it `unknown CAT (asset_id 0x...)` and flag risk: unknown CATs can be worthless or scammy clones with deceptively similar names.

For every NFT, fetch the launcher_id. Don't bulk-fetch off-chain metadata — that's slow and out of scope. Surface the launcher_id and tell the user to verify the NFT in their wallet before taking.

## Fetch market prices

For each side:

- **XCH** — current spot price from chia-explorer (USD).
- **Known CATs** — chia-explorer does not currently price CATs. State this explicitly and leave the CAT side unvalued. Don't invent prices.
- **NFTs** — same. No automatic floor price lookup.

Total each side's USD value where possible. If a side contains an unknown CAT or an NFT, mark the total as "partial: includes unvalued asset".

## Compare and surface verdict

Compute the imbalance from the user's perspective (assume the user is *taking* the offer, so they receive the offered side and give the requested side):

- If both sides are fully valued in fiat:
  - `imbalance_pct = (requested_value - offered_value) / offered_value * 100`
  - Negative imbalance → user receives more than they give → favourable.
  - Positive imbalance → user gives more than they receive → unfavourable.
- If either side has an unvalued asset, skip the percentage but still describe both sides side by side.

Verdict thresholds (against `$max_unfavourable_pct`):

- imbalance < 0 → `FAVOURABLE` (user benefits)
- `0 ≤ imbalance ≤ max_unfavourable_pct` → `NEUTRAL`
- imbalance > `max_unfavourable_pct` → `UNFAVOURABLE` (recommend declining)

Risk flags (add any that apply):

- `unknown_cat` — at least one CAT on either side has an unrecognised asset_id.
- `nft_present` — an NFT is on either side; user must verify launcher_id matches the expected collection.
- `large_amount` — total value on a fully-priced side exceeds 1000 XCH equivalent.
- `multi_asset_side` — three or more distinct assets on a single side. Common in dump-bundling scams.
- `decoded_but_unverifiable` — at least one asset's puzzle could be decoded but classification was ambiguous.

## Compose the report

Plain-text report, surfaced inline in the conversation. Don't push to a channel — this is interactive.

```
Offer safety check

  Verdict:    UNFAVOURABLE (you'd give 12.3% more than you receive)
  Risk flags: unknown_cat, multi_asset_side

YOU RECEIVE (the offered side)
  + 1.000 XCH                                ~$50.00
  + 500 unknown CAT (asset_id 0xabc...123)   unpriced

YOU GIVE (the requested side)
  - 1.200 XCH                                ~$60.00 (rounded)
  - 1 NFT launcher 0xdef...456               unpriced

NOTES
  - Unknown CAT on the offered side. Don't take unless you've verified
    the asset_id matches the project you think it does. Names can be
    spoofed; asset_ids cannot.
  - NFT on the requested side. Confirm in your wallet that this is the
    launcher you intend to give up.
  - You handle the trade in your wallet — this check does not sign.
```

## Hard rules

- **Read-only.** Never take the offer. Never call any wallet MCP. Just report.
- **Asset_id and launcher_id are truth.** Names and tickers can be spoofed; identifiers cannot. Always show the full id (truncated for readability, full on request).
- **Unpriced ≠ valueless.** Don't tell the user a CAT is worthless because you can't price it. Just say "unpriced".
- **No advice on whether to take.** Verdict is mechanical (above or below the imbalance threshold). The user decides.

## Recovery patterns

- **Decode fails.** Report failure with the verbatim error. Common cause: truncated paste.
- **Price tool fails.** Skip fiat valuations; render the asset list anyway. Emit `STATUS: partial`.
- **Multi-NFT or multi-CAT offer.** Render every asset. Don't summarise away detail; the user needs to see what's actually in the offer.

## Output

```
STATUS: success | partial | failed | aborted
VERDICT: FAVOURABLE | NEUTRAL | UNFAVOURABLE | UNPRICEABLE
IMBALANCE_PCT: <decimal or none>
OFFERED_SIDE_USD: <total or partial> | none
REQUESTED_SIDE_USD: <total or partial> | none
RISK_FLAGS: <comma-separated, or none>
ARTIFACT: none
REASON: <one line, only when STATUS is failed, partial, or aborted>
```

