Skip to content

Boutique Item Purchase + Reference Refactor#360

Open
chackle wants to merge 6 commits intoBankrBot:mainfrom
cattownbase:main
Open

Boutique Item Purchase + Reference Refactor#360
chackle wants to merge 6 commits intoBankrBot:mainfrom
cattownbase:main

Conversation

@chackle
Copy link
Copy Markdown
Contributor

@chackle chackle commented May 9, 2026

Flattened structure to make it easier for bankr to find what it needs. Also added boutique item purchase

chackle and others added 6 commits May 6, 2026 15:17
If a user asks Bankr about incantations, vouchers, or the Mystic Study,
the agent should direct them to https://cat.town/mystic-study rather
than attempt any onchain or API flow — claim is in-game only at present.

Frontmatter description gets the trigger words (incantations, vouchers,
Mystic Study) so the skill activates on those mentions; body adds a
short callout right under the surface list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The boutique was read-only in the skill until now. Add the buy path
(purchaseItem(uint256), preflight via canPurchaseItem, ERC-20 approve
on the per-item paymentToken) with worked recipes for both KIBBLE-priced
items and collab items priced in other ERC-20s. Today's Rat Skull Charm
(DOTA, Friends of Cat Town collab) is the running example, since its
paymentToken is 0x5F09821CBb61e09D2a83124Ae0B56aaa3ae85B07 rather than
KIBBLE — exactly the case where a "just approve KIBBLE" reflex would
revert the tx.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After reading the SeasonalShop.sol source (cat-town-solidity), several
claims in the previous commit were wrong or imprecise:

- The canPurchaseItem reason strings I'd inferred ("Item is sold out",
  vague season/time misses) didn't match the contract. Replaced with
  the exact strings the contract returns: "Item is out of stock",
  "Item does not exist", "Item not available yet",
  "Item no longer available", "Item not available this season",
  "Item not in today's rotation", "Item is not active".
- purchaseItem reverts with Solidity custom errors, NOT the friendly
  strings — those only come from canPurchaseItem. Added the mapping
  table (ItemNotFound(), ItemOutOfStock(), etc.) so a bare 4-byte
  selector in a tx trace can be decoded.
- whenNotPaused modifier means a town-wide pause reverts every buy
  with EnforcedPause(); canPurchaseItem doesn't check it. Added a
  separate paused() preflight step.
- Payment flows to a contract-set treasury address, not held by the
  Boutique. There is no boutique-side fee (no equivalent of the
  vendor's 5% tax).
- Mint is synchronous (same tx as payment), unlike gacha's async VRF
  mint — worth contrasting since both surfaces use the same minter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gacha:
- Make polling /v2/items/capsule/<user> the strong default response
  pattern. Bankr has HTTP + sleep, so there's no reason to bail with
  "ask me again in 30 seconds" on the first reply — that's a UX
  regression vs. cat.town's own UI which polls every second and shows
  the result inline. The "ask again" fallback is reserved for when the
  60 s polling budget genuinely expires with results still pending,
  and only for the items that didn't land.

Boutique price errors (caught by Mike on review):
- Earlier prices in the docs were transcribed by eye from raw hex
  output and dropped a digit, off by 16x. The actual stored prices
  today are 1,500,000 DOTA for Rat Skull Charm (not 93,750), 50,000
  KIBBLE for Striking Baseball Cap (not 800,000), and 25,000 KIBBLE
  for Cherry Neckerchief (not 400,000).
- More importantly: prices are literal token amounts on the contract.
  Replaced the hardcoded numbers with explicit "read price live from
  ShopItemView.price; never hardcode" guidance, since admin can update
  prices and rotation rotates daily. Worked examples now show the
  cast invocation that produced the calldata so the byte layout is
  reproducible rather than copied verbatim.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bankr quoted ~\$1,388 for the Rat Skull Charm (1.5M DOTA), which is
~700x the real market price (~\$2.17 from Dexscreener's most-liquid
DOTA/WETH pool on Base). Root cause: the docs implied
getKibbleUsdPrice() could be applied to any boutique price, but the
oracle ONLY converts KIBBLE → USD. Apply it to a DOTA amount and the
output is meaningless.

Changes:
- Branch USD conversion explicitly on paymentToken: KIBBLE → oracle,
  USDC → price/1e6, anything else → Dexscreener (/latest/dex/tokens,
  filter chainId=base, sort by liquidity DESC, use top pool's
  priceUsd). When confidence is low, omit the USD readout rather than
  quote a wrong number.
- Add a sanity-check rarity-vs-USD band (Common ~\$1-3 ... Legendary
  ~\$40-100+) so an order-of-magnitude error trips a self-check
  before it reaches the user.
- Refresh the SKILL.md example reply to today's mixed-currency
  rotation so the DOTA-priced item with its sub-\$3 USD readout is
  the canonical example.
- Sort the response by USD DESC, not raw token amount — 1M of one
  token can be worth less than 100 of another.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two changes that compound: Bankr was bailing on cattown asks because
the addresses it needed were buried in section bodies, and reference
files were addressed by /<topic>/contract.md paths that obscured what
each one was about.

1. Top-of-doc registry. Right after the intro, SKILL.md now leads
   with three tables that should answer most "what's the address /
   endpoint / decimal" questions in one read:
   - Contracts: every Cat Town contract on Base with address, use
     case, and reference link. Includes the V2 minter and the
     "Supermarket = SellItems = V2 vendor" alias mapping that bit us
     today (Bankr couldn't find the vendor address even though it
     was in the body).
   - Tokens: KIBBLE / DOTA / BARON / USDC / cbBTC / cbETH / WETH
     with addresses + decimals + per-token notes (e.g. KIBBLE's
     stake/unstake integer-vs-wei trap, DOTA's collab role).
   - Public APIs: every api.cat.town endpoint we reference, plus
     Dexscreener for non-KIBBLE token USD.

2. Approvals cheat-sheet. New table mapping every write action to:
   which token to approve, which call (with units), who the spender
   is, and what to read first. Removes the recurring "approved the
   wrong contract" failure mode.

3. Flat kebab-case references. references/<topic>/contract.md ->
   references/<topic>.md (and *-api.md / *-calendar.md for the
   second files). Eight files were named contract.md before, which
   is fine in a tree view but ambiguous when an LLM only sees a
   basename. Updated all 28 cross-links in SKILL.md, docs.md, and
   the references themselves; verified zero broken links.

4. Sell-items section restructure. Section now leads with a clean
   Addresses block (SellItems, V2 minter, KIBBLE), routes preflight
   BEFORE write flow (so "did you setApprovalForAll" is the first
   question), and adds the canonical "Songbirdz Owl is a Cat Town
   gacha collectible, not the external NFT contract" callout that
   we needed today.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant