Complete the market loop (browse + buy + sell). POST auctionhouse (FutISStart)
lists an owned club item -> profile.listings + returns {id:tradeId}. tradePile
builds a validated auction record per listing from the owned item + prices
(freeze-safe, same 0x18013e410 shape). DELETE trade/{id} removes the listing.
fut_store gains list_for_sale/listings/remove_listing (tradeId space 900500000+).
test_market_buy.py extended with sell/delist checks (temp profile, no real-save
mutation): list -> tradePile shows it with prices -> delist empties it. All pass.
Read-only contract suite still 311/311. Functional (FIFA's exact sell params)
pending live test; freeze-safe by construction.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PN5bmpDVQR1aXgefyWAt7o
trade_route now resolves the auction from its tradeId and, on buy-now
(bid >= buyNowPrice), spends coins + grants the won card to the club + echoes
the CLOSED auction (FutISOfferTrade shape). Reuses the validated auction record
(0x18013e410) so it stays freeze-safe; whether FIFA surfaces the won item
post-buy is functional (needs live test). Insufficient funds -> 461.
tools/test_market_buy.py: offline unit test on a TEMP profile (never touches the
real save) -- verifies coin deduction, card grant, closed-auction shape, and the
461 path. PASS. Read-only contract suite still 311/311.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PN5bmpDVQR1aXgefyWAt7o