Skip to content

feat(collection): multi-item DID-attributed mint + bech32 DID decode#10

Merged
MichaelTaylor3d merged 1 commit into
mainfrom
feat/collection-bulk-mint-funding
Jul 10, 2026
Merged

feat(collection): multi-item DID-attributed mint + bech32 DID decode#10
MichaelTaylor3d merged 1 commit into
mainfrom
feat/collection-bulk-mint-funding

Conversation

@MichaelTaylor3d

@MichaelTaylor3d MichaelTaylor3d commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes DIG-Network/dig_ecosystem#199 (dkackman's 203-item collection blocked) and DIG-Network/dig_ecosystem#198 (bech32 did:chia: decode).

collection mint refused any manifest with more than one item. Root cause: Chia's coin-value conservation is bundle-wide, not per-coin — each item's IntermediateLauncher "prints" 1 mojo (a 0-value intermediate coin's own spend creates a 1-mojo singleton launcher), and that mojo must be donated by another coin in the same bundle. The DID's own update spend conserves its exact value, so it can fund at most one item's worth on its own. A real N>1 mint needs a separate XCH funding coin.

What changed

  • digstore_chain::collection::build_collection_mint_funded(_in) — reuses the existing (already N-agnostic) build_collection_mint_in per-item loop and additionally spends a separate XCH coin contributing items.len() mojos, returning any excess as change (never silently burned as network fee). Single-item behavior (build_collection_mint) is untouched.
  • CLI (collection mint) — selects a funding coin via the existing scan_and_select_funding for items.len() > 1, calls the funded builder, and removes the old >1 item refusal.
  • digstore_chain::did::decode_bech32_did + CLI parse_did_arg — accepts a did:chia:1… bech32m address (Sage/CNI's display form) in addition to 64-hex, on every --did flag (collection mint/show, nft mint --did). parse_launcher_id (used for non-DID ids like --nft) is untouched.
  • SPEC.md §11.1/§11.2 — documents the --did bech32/hex acceptance and the N=1-vs-N>1 funding contract.
  • docs.dig.netnft-developers.md + command-reference.md updated (bulk manifest minting, bech32 DID acceptance).
  • Superproject DEVELOPMENT_LOG.md — durable realization on bundle-wide coin conservation / the IntermediateLauncher funding mechanic.

Blast radius (gitnexus, before editing)

  • build_collection_mint_in (upstream): LOW risk, 2 direct callers (collection.rs mint/run) — both are the CLI file I edited; no other consumers.
  • parse_launcher_id (upstream): CRITICAL risk, 4 direct callers (nft mint/transfer, collection mint/show) — left completely unchanged; a new parse_did_arg wrapper was added instead, so that blast radius is unaffected.

Verification

  • Simulator N>1 proof (the required proof): build_collection_mint_funded_in_validates_on_simulator — a real N=3 DID-attributed mint, funded by a separate 10-mojo XCH coin, validates under Chia consensus in-process; asserts the 7-mojo change coin lands back at the funder (not burned as fee). build_collection_mint_funded_rejects_underfunded_coin proves the insufficient-funds message.
  • bech32 DID decode: round-trip test against a known vector + dkackman's own reported DID string; malformed/wrong-prefix rejection tests, at both the chain-crate and CLI layers.
  • Installed-binary integration (§3.5): after cargo install --path crates/digstore-cli --force --locked, ran the installed digstore.exe directly (not just cargo test):
    • collection mint with a 203-item manifest (dkackman's exact real-world size) --dry-run: no longer hits the old "single DID-attributed item" refusal; proceeds through funding-coin selection and reaches the same "does not own DID" failure (exit 4) the single-item path already hits under the offline mock.
    • collection show --did did:chia:1s8j4p... decodes to 81e55083864f29bbffed17234f0120b3ba51c69b69a9d785f9bcfda68ebc5d56 (exit 0).
    • Malformed bech32 --did rejected with a clear message (exit 2).
    • Single-item mint regression-checked unchanged (same exit 4 as before).
  • Full test suites green: cargo test -p digstore-chain (209 passed), cargo test -p digstore-cli (all suites green, incl. cli_assets.rs 19/19).
  • cargo fmt --all -- --check clean; cargo clippy -p digstore-chain -p digstore-cli --all-targets --all-features -- -D warnings clean.
  • Coverage: cargo llvm-cov is blocked locally by a pre-existing Windows/cmake toolchain issue unrelated to this change (a libz-sys build script failure under the llvm-cov instrumented profile); this repo has no CI coverage gate configured yet (a separate, pre-existing gap, not introduced here). Every new function has dedicated tests including error paths.

SemVer

Minor (0.9.10.10.0) — backwards-compatible new capability (feat:): multi-item collection mint + bech32 DID acceptance, no removed/changed public API, no format/schema break.

Follow-up (flagged, not fixed here — separate lane)

chip35_dl_coin's core/src/collection.rs::build_bulk_mint (the hub NFT Studio's on-chain twin) has the same missing N-launcher funding gap — it has no funding-coin parameter at all. Left untouched here per single-writer (a chip35 lane is active on #189); noting on #199 for follow-up.

Test plan

  • cargo test -p digstore-chain — 209 passed
  • cargo test -p digstore-cli — all suites green
  • cargo fmt --all -- --check — clean
  • cargo clippy -p digstore-chain -p digstore-cli --all-targets --all-features -- -D warnings — clean
  • Simulator N=3 funded collection mint validates under consensus
  • Installed-binary smoke test: 203-item --dry-run, bech32 DID decode, malformed DID rejection, single-item regression

collection mint refused any manifest with more than one item because the DID
singleton alone can only fund one intermediate-launcher coin (Chia's coin-value
conservation is bundle-wide: an IntermediateLauncher's 0-value intermediate coin
"prints" 1 mojo per item when it creates the singleton launcher, and that mojo
must be donated by another coin in the same bundle — the DID's own update spend
conserves its exact value and cannot supply it for more than one item).

Add build_collection_mint_funded(_in) to digstore-chain::collection: it reuses
the existing (already N-agnostic) build_collection_mint_in per-item loop and
additionally spends a separate XCH coin contributing items.len() mojos, with any
excess returned as change rather than silently burned as network fee. Proven on
the in-process Chia Simulator with a real N=3 funded mint that validates under
consensus (build_collection_mint_funded_in_validates_on_simulator).

Wire the CLI: `collection mint` now selects a funding coin via the existing
scan_and_select_funding for N>1 manifests and calls the funded builder, removing
the old ">1 item" refusal. The single-item path is unchanged (still funds the one
launcher from the DID's own coin, no separate funding coin needed).

Also decode `did:chia:1…` bech32m DID identifiers inline on every --did flag
(collection mint/show, nft mint --did), in addition to 64-hex, via a new
digstore_chain::did::decode_bech32_did + CLI parse_did_arg wrapper — closes the
ergonomics gap wallets like Sage/CNI create by displaying DIDs only in bech32m.

Installed-binary integration proof: a 203-item collection mint --dry-run (the
exact size a real user hit this on) no longer returns the old refusal and
reaches the same "does not own DID" failure the single-item path already hit
under the offline mock; a bech32 --did decodes to the same launcher id hex would.

Closes #199, #198
@MichaelTaylor3d MichaelTaylor3d merged commit b635925 into main Jul 10, 2026
11 checks passed
@MichaelTaylor3d MichaelTaylor3d deleted the feat/collection-bulk-mint-funding branch July 10, 2026 01:11
MichaelTaylor3d added a commit that referenced this pull request Jul 10, 2026
…10)

collection mint refused any manifest with more than one item because the DID
singleton alone can only fund one intermediate-launcher coin (Chia's coin-value
conservation is bundle-wide: an IntermediateLauncher's 0-value intermediate coin
"prints" 1 mojo per item when it creates the singleton launcher, and that mojo
must be donated by another coin in the same bundle — the DID's own update spend
conserves its exact value and cannot supply it for more than one item).

Add build_collection_mint_funded(_in) to digstore-chain::collection: it reuses
the existing (already N-agnostic) build_collection_mint_in per-item loop and
additionally spends a separate XCH coin contributing items.len() mojos, with any
excess returned as change rather than silently burned as network fee. Proven on
the in-process Chia Simulator with a real N=3 funded mint that validates under
consensus (build_collection_mint_funded_in_validates_on_simulator).

Wire the CLI: `collection mint` now selects a funding coin via the existing
scan_and_select_funding for N>1 manifests and calls the funded builder, removing
the old ">1 item" refusal. The single-item path is unchanged (still funds the one
launcher from the DID's own coin, no separate funding coin needed).

Also decode `did:chia:1…` bech32m DID identifiers inline on every --did flag
(collection mint/show, nft mint --did), in addition to 64-hex, via a new
digstore_chain::did::decode_bech32_did + CLI parse_did_arg wrapper — closes the
ergonomics gap wallets like Sage/CNI create by displaying DIDs only in bech32m.

Installed-binary integration proof: a 203-item collection mint --dry-run (the
exact size a real user hit this on) no longer returns the old refusal and
reaches the same "does not own DID" failure the single-item path already hit
under the offline mock; a bech32 --did decodes to the same launcher id hex would.

Closes #199, #198

Co-Authored-By: Claude <noreply@anthropic.com>
MichaelTaylor3d added a commit that referenced this pull request Jul 10, 2026
…10)

collection mint refused any manifest with more than one item because the DID
singleton alone can only fund one intermediate-launcher coin (Chia's coin-value
conservation is bundle-wide: an IntermediateLauncher's 0-value intermediate coin
"prints" 1 mojo per item when it creates the singleton launcher, and that mojo
must be donated by another coin in the same bundle — the DID's own update spend
conserves its exact value and cannot supply it for more than one item).

Add build_collection_mint_funded(_in) to digstore-chain::collection: it reuses
the existing (already N-agnostic) build_collection_mint_in per-item loop and
additionally spends a separate XCH coin contributing items.len() mojos, with any
excess returned as change rather than silently burned as network fee. Proven on
the in-process Chia Simulator with a real N=3 funded mint that validates under
consensus (build_collection_mint_funded_in_validates_on_simulator).

Wire the CLI: `collection mint` now selects a funding coin via the existing
scan_and_select_funding for N>1 manifests and calls the funded builder, removing
the old ">1 item" refusal. The single-item path is unchanged (still funds the one
launcher from the DID's own coin, no separate funding coin needed).

Also decode `did:chia:1…` bech32m DID identifiers inline on every --did flag
(collection mint/show, nft mint --did), in addition to 64-hex, via a new
digstore_chain::did::decode_bech32_did + CLI parse_did_arg wrapper — closes the
ergonomics gap wallets like Sage/CNI create by displaying DIDs only in bech32m.

Installed-binary integration proof: a 203-item collection mint --dry-run (the
exact size a real user hit this on) no longer returns the old refusal and
reaches the same "does not own DID" failure the single-item path already hit
under the offline mock; a bech32 --did decodes to the same launcher id hex would.

Closes #199, #198

Co-Authored-By: Claude <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