feat(collection): multi-item DID-attributed mint + bech32 DID decode#10
Merged
Merged
Conversation
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
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes DIG-Network/dig_ecosystem#199 (dkackman's 203-item collection blocked) and DIG-Network/dig_ecosystem#198 (bech32
did:chia:decode).collection mintrefused any manifest with more than one item. Root cause: Chia's coin-value conservation is bundle-wide, not per-coin — each item'sIntermediateLauncher"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 ownupdatespend 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_inper-item loop and additionally spends a separate XCH coin contributingitems.len()mojos, returning any excess as change (never silently burned as network fee). Single-item behavior (build_collection_mint) is untouched.collection mint) — selects a funding coin via the existingscan_and_select_fundingforitems.len() > 1, calls the funded builder, and removes the old>1 itemrefusal.digstore_chain::did::decode_bech32_did+ CLIparse_did_arg— accepts adid:chia:1…bech32m address (Sage/CNI's display form) in addition to 64-hex, on every--didflag (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--didbech32/hex acceptance and the N=1-vs-N>1 funding contract.docs.dig.net—nft-developers.md+command-reference.mdupdated (bulk manifest minting, bech32 DID acceptance).DEVELOPMENT_LOG.md— durable realization on bundle-wide coin conservation / theIntermediateLauncherfunding mechanic.Blast radius (gitnexus, before editing)
build_collection_mint_in(upstream): LOW risk, 2 direct callers (collection.rsmint/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 newparse_did_argwrapper was added instead, so that blast radius is unaffected.Verification
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_coinproves the insufficient-funds message.cargo install --path crates/digstore-cli --force --locked, ran the installeddigstore.exedirectly (not justcargo test):collection mintwith 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 to81e55083864f29bbffed17234f0120b3ba51c69b69a9d785f9bcfda68ebc5d56(exit 0).--didrejected with a clear message (exit 2).cargo test -p digstore-chain(209 passed),cargo test -p digstore-cli(all suites green, incl.cli_assets.rs19/19).cargo fmt --all -- --checkclean;cargo clippy -p digstore-chain -p digstore-cli --all-targets --all-features -- -D warningsclean.cargo llvm-covis blocked locally by a pre-existing Windows/cmake toolchain issue unrelated to this change (alibz-sysbuild 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.1→0.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'score/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 passedcargo test -p digstore-cli— all suites greencargo fmt --all -- --check— cleancargo clippy -p digstore-chain -p digstore-cli --all-targets --all-features -- -D warnings— clean--dry-run, bech32 DID decode, malformed DID rejection, single-item regression