Nft provenance
Skill Spacetime-Technology/chia-skills/skills/nft-provenance
Claude Code skills that turn chia-explorer into finished workflows: address watches, price alerts, offer safety checks, NFT provenance, invoice watching.
npx -y skills add Spacetime-Technology/chia-skills --skill nft-provenanceAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Trace a Chia NFT from mint through every transfer to its current owner. Given a launcher_id (or any coin in the lineage), walks the full chain of custody, classifies each step, and surfaces the current holder address. Use when the user wants to verify NFT history, check an NFT before buying, prove authenticity, or research a collection. Accepts launcher_id, include_metadata as arguments for programmatic invocation.
SKILL.md
6.0 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it
NFT provenance
You are tracing a Chia NFT from its mint to its current owner. The launcher coin (or any coin in the singleton's lineage) is enough — you follow the eve coin forward through every singleton spend, classifying each step and labelling any addresses chia-explorer recognises.
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. Usesget_coin_by_name,get_coin_records_by_parent_ids,get_puzzle_and_solution,decompile_puzzle,puzzle_hash_to_address,list_prefarm_addresses.
Resolve inputs
You need: $launcher_id, $include_metadata.
$launcher_id— the NFT singleton's launcher coin id as0x...hex (32 bytes / 64 hex chars). Required.$include_metadata—trueorfalse. Defaultfalse. If true, the skill will try to surface on-chain metadata URIs (data_uris, metadata_uris, license_uris). It will not fetch IPFS / HTTP content; just print the URIs.
Resolve: arguments → context → ask user.
Validate $launcher_id (32 bytes hex).
Note: if the user gives you a coin id rather than a launcher, you can still find the lineage by walking back to the launcher; do that first via coin-lineage-style traversal. Identify the launcher as the singleton's root coin (its puzzle decompiles as a launcher / eve puzzle).
Walk the singleton
Start from the launcher coin. For each step in the singleton chain:
- Look up the coin record by name. It should be spent (the eve coin always is). Capture the spent height.
- Get puzzle and solution at the spent block. Decompile.
- The first child of the launcher coin is the eve coin. From there, each subsequent NFT generation is a single child of the previous coin (singletons have a single child).
- Resolve the puzzle hash to an address. Check the prefarm registry for a label. Capture the address as the current holder at the end of that step.
- Move to the child coin. Repeat.
Stop when you reach a coin that is unspent. That coin is the current state of the NFT, and its puzzle hash maps to the current holder address.
Detect transfers vs no-op spends
Not every singleton spend is a transfer of ownership. The NFT can be:
- Transferred — the inner puzzle's owner changed. The puzzle hash post-spend resolves to a new address.
- Re-minted / state-updated — metadata changed (uri list updated, royalty tweaked) but ownership didn't.
- DID-locked / DID-released — assigned to or unassigned from a DID.
In the report, label each step as MINT, TRANSFER, METADATA_UPDATE, DID_ASSIGN, DID_RELEASE, or OTHER.
Compose the report
NFT provenance — launcher 0xabc...123
CURRENT HOLDER: xch1zzz...mno (no label)
TOTAL TRANSFERS: 3
AGE: ~62 days since mint
LINEAGE
MINT block 6,500,001 → xch1aaa...bbb (creator)
TRANSFER block 6,510,210 → xch1ccc...ddd (no label)
METADATA_UPDATE block 6,515,000 (uri added, owner unchanged)
TRANSFER block 6,525,800 → xch1eee...fff (no label)
TRANSFER block 6,530,915 → xch1zzz...mno (no label) ← current
METADATA (latest spend)
data_uri: ipfs://bafy.../image.png
metadata_uri: ipfs://bafy.../metadata.json
license_uri: ipfs://bafy.../license.txt
Full launcher_id: 0xabc123...
Current owner address: xch1zzz...mno
If $include_metadata = false, omit the METADATA section.
For very long lineages (hundreds of spends — rare but possible for active NFTs), summarise: show first 3 steps, last 5 steps, and a ... N intermediate steps omitted ... line.
Risk and authenticity notes
Surface at the bottom when applicable:
- Mint creator address has a chia-explorer label — flag if it matches a known scam-list (no built-in scam list yet; just note the label).
- NFT passed through a labelled exchange address — useful for buyers verifying secondary-market provenance.
- Owner currently a DID — note the DID identifier and that the NFT is bound to that DID.
- High transfer rate — if transfers happen many times per hour, flag it: could be wash-trading or a hot trading account.
Don't editorialise on whether the NFT is "legit". The on-chain trace doesn't tell you that.
Hard rules
- Read-only. Never sign, never claim, never mint. If the user wants to buy or sell, they go to a marketplace.
- launcher_id is canonical. Names and titles can be spoofed; launcher_ids cannot. Always print the full launcher in the report footer.
- Don't fetch off-chain content. If
$include_metadatais true, show the URIs only. The user opens them themselves. - Hop cap doesn't apply — singletons have a deterministic chain. Walk it to the end.
Recovery patterns
- Launcher not found. Emit
STATUS: failed,REASON: launcher not found. - Singleton chain broken (a step's child can't be found) — note the break, report what you walked, emit
STATUS: partial. - Puzzle classification ambiguous on some step. Mark that step
OTHERand continue.
Output
STATUS: success | partial | failed | aborted
LAUNCHER_ID: <full 0x... hex>
CURRENT_HOLDER: <full address>
CURRENT_HOLDER_LABEL: <registry label> | none
TRANSFERS: <count of TRANSFER steps>
TOTAL_STEPS: <count of all spends in the chain>
AGE_BLOCKS: <peak - mint_height>
MINTED_AT_HEIGHT: <int>
RISK_NOTES: <comma-separated tags> | none
ARTIFACT: none
REASON: <one line, only when STATUS is failed, partial, or aborted>