From 3df9060d60a69c65a473454e019634e8347ad67e Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Sat, 18 Jul 2026 16:46:28 -0700 Subject: [PATCH 1/3] =?UTF-8?q?chore:=20begin=20dig-l1-wallet=20=E2=86=92?= =?UTF-8?q?=20dig-wallet-backend=20migration=20(#1005)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude From 52c3a8d0cd43e11c0e960fe02cf16b66d7a717e2 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Sat, 18 Jul 2026 16:52:03 -0700 Subject: [PATCH 2/3] feat(digstore-chain)!: migrate off dig-l1-wallet onto dig-wallet-backend engine seam Replace the deprecated dig-l1-wallet coin-selection primitive with dig-wallet-backend v0.4 (engine seam), per epic #998. The new engine seam speaks in chia_protocol::Coin natively, so the chia-query CoinRecord conversion dance (to_record/from_record + bytes32_to_hex/ coin_record_to_protocol_coin) is removed and the chia-query direct dep dropped. select_for_spend is now infallible; select_for_consolidation maps WalletError to ChainError. digstore keeps its own COIN_CAP of 50 (bundle cost ceiling) rather than the backend's general default of 500. Also removes the now-obsolete [patch] redirect for dig-l1-wallet's transitive dig-keystore in the root Cargo.toml and the dig-l1-wallet entry from deny.toml's git-source allowlist. Adds a regression test asserting the absence of any dig-l1-wallet dependency. Consumer adapts to the new interface; the backend is not reshaped. Closes #1005. Refs #998. Co-Authored-By: Claude --- Cargo.lock | 249 ++++++++++--------------- Cargo.toml | 15 +- crates/digstore-chain/Cargo.toml | 16 +- crates/digstore-chain/src/selection.rs | 120 +++++------- deny.toml | 5 - 5 files changed, 158 insertions(+), 247 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e471b6c..36cbd3f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1246,30 +1246,6 @@ dependencies = [ "hex-literal", ] -[[package]] -name = "chia-query" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d28ca28823fac6bf6ea214477b370c87a7adaaddacc6d33bb275a20db830b19c" -dependencies = [ - "chia", - "chia-wallet-sdk", - "clvmr", - "futures-util", - "hex", - "log", - "openssl", - "openssl-sys", - "rand 0.8.7", - "reqwest", - "serde", - "serde_json", - "sha2 0.10.9", - "thiserror 2.0.18", - "tokio", - "tokio-tungstenite", -] - [[package]] name = "chia-sdk-client" version = "0.30.0" @@ -2122,6 +2098,40 @@ dependencies = [ "cipher", ] +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.118", +] + [[package]] name = "data-encoding" version = "2.11.0" @@ -2220,61 +2230,33 @@ dependencies = [ ] [[package]] -name = "dig-keystore" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dfa3f409601b5dc12de4b00eb7112ca2bd31ae9757a8373fdeca89e3fb4d0f6" +name = "dig-resolver" +version = "0.1.0" dependencies = [ - "aes-gcm", - "argon2", - "chia-bls 0.26.0", - "crc32fast", + "chia-protocol", + "digstore-chain", "hex", - "parking_lot", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "thiserror 1.0.69", - "zeroize", + "tokio", ] [[package]] -name = "dig-l1-wallet" -version = "0.3.0" -source = "git+https://github.com/DIG-Network/dig-l1-wallet?tag=v0.3.0#fed8758b6aa6644d3109e226f1c1a2f343212cff" +name = "dig-wallet-backend" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "358c03e260019ab36389b4cc82f58185ca1ae0c3b9fd95b2b10f57c324c18545" dependencies = [ - "base64 0.22.1", - "bip39", + "async-trait", "chia", - "chia-puzzle-types", - "chia-puzzles", - "chia-query", "chia-wallet-sdk", - "clvm-traits", - "clvm-utils", "clvmr", - "dig-keystore", - "dirs 6.0.0", + "enumset", + "futures-core", "hex", - "log", - "openssl", - "openssl-sys", - "rand 0.8.7", "serde", "serde_json", - "sha2 0.10.9", "thiserror 2.0.18", "tokio", - "zeroize", -] - -[[package]] -name = "dig-resolver" -version = "0.1.0" -dependencies = [ - "chia-protocol", - "digstore-chain", - "hex", - "tokio", + "tokio-stream", ] [[package]] @@ -2300,7 +2282,7 @@ dependencies = [ [[package]] name = "digstore-chain" -version = "0.16.0" +version = "0.17.0" dependencies = [ "aes-gcm", "anyhow", @@ -2310,7 +2292,6 @@ dependencies = [ "chia", "chia-protocol", "chia-puzzles", - "chia-query", "chia-sdk-coinset", "chia-sdk-test", "chia-sdk-types", @@ -2320,9 +2301,9 @@ dependencies = [ "clvmr", "datalayer-driver", "dig-constants", - "dig-l1-wallet", + "dig-wallet-backend", "digstore-core", - "dirs 5.0.1", + "dirs", "getrandom 0.2.17", "hex", "hex-literal", @@ -2339,7 +2320,7 @@ dependencies = [ [[package]] name = "digstore-chunker" -version = "0.16.0" +version = "0.17.0" dependencies = [ "digstore-core", "hex", @@ -2349,7 +2330,7 @@ dependencies = [ [[package]] name = "digstore-cli" -version = "0.16.0" +version = "0.17.0" dependencies = [ "anstream 0.6.21", "anstyle", @@ -2372,7 +2353,7 @@ dependencies = [ "digstore-remote", "digstore-stage", "digstore-store", - "dirs 5.0.1", + "dirs", "flate2", "getrandom 0.2.17", "globset", @@ -2415,7 +2396,7 @@ dependencies = [ [[package]] name = "digstore-core" -version = "0.16.0" +version = "0.17.0" dependencies = [ "aes-gcm-siv", "hex", @@ -2512,7 +2493,7 @@ dependencies = [ [[package]] name = "digstore-remote" -version = "0.16.0" +version = "0.17.0" dependencies = [ "async-trait", "axum", @@ -2522,7 +2503,7 @@ dependencies = [ "digstore-crypto", "digstore-host", "digstore-store", - "dirs 5.0.1", + "dirs", "futures-util", "getrandom 0.2.17", "hex", @@ -2570,7 +2551,7 @@ dependencies = [ [[package]] name = "digstore-subscription" -version = "0.16.0" +version = "0.17.0" dependencies = [ "async-trait", "digstore-core", @@ -2597,16 +2578,7 @@ version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ - "dirs-sys 0.4.1", -] - -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys 0.5.0", + "dirs-sys", ] [[package]] @@ -2627,22 +2599,10 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", - "redox_users 0.4.6", + "redox_users", "windows-sys 0.48.0", ] -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users 0.5.2", - "windows-sys 0.61.2", -] - [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -2650,7 +2610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users 0.4.6", + "redox_users", "winapi", ] @@ -2776,6 +2736,28 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enumset" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "839c4174b41e75c8f7306110b2c51996a293b8d1d850edd529011841d9fede7d" +dependencies = [ + "enumset_derive", + "serde", +] + +[[package]] +name = "enumset_derive" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd536557b58c682b217b8fb199afdff47cd3eff260623f19e77074eb073d63a" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -3493,11 +3475,9 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2 0.6.4", - "system-configuration", "tokio", "tower-service", "tracing", - "windows-registry", ] [[package]] @@ -3612,6 +3592,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.1.0" @@ -5077,17 +5063,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "redox_users" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" -dependencies = [ - "getrandom 0.2.17", - "libredox", - "thiserror 2.0.18", -] - [[package]] name = "regalloc2" version = "0.15.1" @@ -5139,7 +5114,6 @@ checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", "bytes", - "encoding_rs", "futures-channel", "futures-core", "futures-util", @@ -5153,7 +5127,6 @@ dependencies = [ "hyper-util", "js-sys", "log", - "mime", "native-tls", "percent-encoding", "pin-project-lite", @@ -5227,7 +5200,7 @@ checksum = "0811a16d45e5b4f102c7095fe43ec63afe8c76d85ae799522d0b9f247975aa61" dependencies = [ "anyhow", "cargo_metadata", - "dirs 5.0.1", + "dirs", "docker-generate", "hex", "regex", @@ -5978,27 +5951,6 @@ dependencies = [ "syn 2.0.118", ] -[[package]] -name = "system-configuration" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" -dependencies = [ - "bitflags 2.13.0", - "core-foundation 0.9.4", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tap" version = "1.0.1" @@ -6231,6 +6183,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + [[package]] name = "tokio-tungstenite" version = "0.24.0" @@ -7265,17 +7229,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - [[package]] name = "windows-result" version = "0.4.1" diff --git a/Cargo.toml b/Cargo.toml index bdcd464a..e9fbf088 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ exclude = ["crates/digstore-prover/guest", "crates/dig-client-wasm"] [workspace.package] edition = "2021" -version = "0.16.0" +version = "0.17.0" license = "GPL-2.0-only" [workspace.dependencies] @@ -13,19 +13,6 @@ sha2 = "0.10" proptest = "1" hex = "0.4" -# dig-l1-wallet (the canonical Rust coin-selection + consolidation primitive, T0b -# of coin-management epic #410) is consumed by `digstore-chain` as a GIT dependency -# pinned to tag v0.3.0 — v0.3.0 (with the `select_for_spend`/`select_for_consolidation` -# API) is NOT on crates.io (only v0.1.0 is). The crate's manifest declares -# `dig-keystore = { version = "0.1", path = "../dig-keystore" }`; when dig-l1-wallet is -# pulled via git, cargo resolves that path dep WITHIN the git source and fails to find -# dig-keystore (the #216 git-consumability seam). This `[patch]` redirects that -# transitive dig-keystore to crates.io v0.1.3 (which satisfies its `^0.1` pin), so the -# git dependency resolves cleanly. Remove this patch once dig-l1-wallet publishes a -# git-consumable / crates.io release. -[patch."https://github.com/DIG-Network/dig-l1-wallet"] -dig-keystore = "=0.1.3" - # Release hardening: keep integer-overflow checks ON in release builds. This # code parses untrusted serialized input and does offset/length arithmetic; # silent wrapping in release would turn a length-overflow bug into a memory diff --git a/crates/digstore-chain/Cargo.toml b/crates/digstore-chain/Cargo.toml index d18ef164..f7b7f35f 100644 --- a/crates/digstore-chain/Cargo.toml +++ b/crates/digstore-chain/Cargo.toml @@ -20,15 +20,13 @@ serde_json = "1" toml = "0.8" thiserror = "1" dirs = "5" -# Canonical coin-selection + consolidation primitive (coin-management epic #410, T0b). -# Provides the capped, high-value-first `select_for_spend`/`select_for_consolidation` -# used by the init/commit/deploy spend paths so ordering + the 50-coin cap + -# NeedsConsolidation are shared across the ecosystem (never hand-rolled — §4.1 / -# Appendix B). Git-pinned to v0.3.0; see the root `[patch]` for the dig-keystore seam. -dig-l1-wallet = { git = "https://github.com/DIG-Network/dig-l1-wallet", tag = "v0.3.0" } -# `select_for_spend` speaks in chia-query's `CoinRecord`; used to convert digstore's -# native `Coin`s into the selector's input type. -chia-query = "0.2" +# Canonical coin-selection + consolidation primitive (dig-wallet-backend, epic #998 — +# supersedes the deprecated predecessor wallet crate). Provides the capped, high-value-first +# `select_for_spend`/`select_for_consolidation` (engine seam) used by the +# init/commit/deploy spend paths so ordering + the coin cap + NeedsConsolidation are +# shared across the ecosystem (never hand-rolled — §4.1 / Appendix B). The engine seam +# speaks in `chia_protocol::Coin` natively; engine-only (this crate never signs). +dig-wallet-backend = { version = "0.4", default-features = false, features = ["engine"] } datalayer-driver = "3" chia = "0.26" chia-protocol = "0.26" diff --git a/crates/digstore-chain/src/selection.rs b/crates/digstore-chain/src/selection.rs index 4d3610b9..6be202a5 100644 --- a/crates/digstore-chain/src/selection.rs +++ b/crates/digstore-chain/src/selection.rs @@ -1,12 +1,12 @@ //! Capped, high-value-first XCH coin selection + consolidation for digstore's //! on-chain money paths (`init` mint, `commit`/`deploy` root-advance). //! -//! This is the digstore-side adapter over the **canonical dig-l1-wallet primitive** -//! (coin-management epic #410, T0b). digstore NEVER hand-rolls coin selection -//! (SYSTEM.md §4.1 / Appendix B): the ordering (descending by amount, tie-broken by -//! coin id), the 50-coin cap ([`COIN_CAP`]), and the `NeedsConsolidation` vs -//! `InsufficientFunds` distinction are the ecosystem-wide contract, expressed once -//! in dig-l1-wallet and reused here. +//! This is the digstore-side adapter over the **canonical dig-wallet-backend +//! primitive** (`dig_wallet_backend::engine::selection`). digstore NEVER hand-rolls +//! coin selection (SYSTEM.md §4.1 / Appendix B): the ordering (descending by amount, +//! tie-broken by coin id), the coin cap ([`COIN_CAP`]), and the `NeedsConsolidation` +//! vs `InsufficientFunds` distinction are the ecosystem-wide contract, expressed once +//! in dig-wallet-backend and reused here. //! //! ## Why a cap //! @@ -27,25 +27,28 @@ //! pure — no network, no signing. use chia_protocol::Coin; -use dig_l1_wallet::coins::selection::{select_for_consolidation, select_for_spend}; -use dig_l1_wallet::coins::tracker::{bytes32_to_hex, coin_record_to_protocol_coin}; -use dig_l1_wallet::{SelectionOutcome, DEFAULT_COIN_CAP}; +use dig_wallet_backend::engine::selection::{ + select_for_consolidation, select_for_spend, SelectionOutcome, +}; use crate::error::{ChainError, Result}; /// Default maximum number of coins a single digstore spend may consume (50). /// -/// Re-exported from dig-l1-wallet's [`DEFAULT_COIN_CAP`] so digstore, the browser/JS -/// spend layer, and every other consumer agree on the exact boundary between -/// "spendable" and "needs consolidation". -pub const COIN_CAP: usize = DEFAULT_COIN_CAP; +/// digstore fixes its own cap so a `init`/`commit`/`deploy` bundle stays within Chia's +/// block/mempool cost ceiling — a smaller bound than dig-wallet-backend's default +/// ([`dig_wallet_backend::engine::selection::DEFAULT_COIN_CAP`]), which serves general +/// wallets. Passed explicitly to every selection call so the browser/JS spend layer and +/// every other digstore consumer agree on the exact boundary between "spendable" and +/// "needs consolidation". +pub const COIN_CAP: usize = 50; /// Outcome of a capped, high-value-first XCH selection over digstore's native coins. /// -/// Mirrors dig-l1-wallet's [`SelectionOutcome`] but speaks in `chia_protocol::Coin` -/// (what the mint/update builders consume) rather than chia-query `CoinRecord`s. The -/// caller matches the variant — `NeedsConsolidation` is never conflated with -/// `InsufficientFunds` (consolidation cannot create value). +/// Mirrors dig-wallet-backend's [`SelectionOutcome`], re-expressed in digstore's own +/// error/variant vocabulary for the mint/update builders. The caller matches the +/// variant — `NeedsConsolidation` is never conflated with `InsufficientFunds` +/// (consolidation cannot create value). #[derive(Debug, Clone)] pub enum XchSelection { /// Coins reaching the target were found within the cap; spend exactly these. @@ -80,60 +83,23 @@ pub enum XchSelection { }, } -/// Convert a native coin into the chia-query `CoinRecord` the selector consumes. -/// -/// Selection looks only at each coin's amount and (for the deterministic tie-break) -/// its coin id, so the block-index / spent / coinbase / timestamp metadata is -/// irrelevant here — unspent-coin placeholders are used. Parent + puzzle hash are -/// preserved exactly so the returned records map back to the original coins. -fn to_record(coin: &Coin) -> chia_query::CoinRecord { - chia_query::CoinRecord { - coin: chia_query::Coin { - parent_coin_info: bytes32_to_hex(&coin.parent_coin_info), - puzzle_hash: bytes32_to_hex(&coin.puzzle_hash), - amount: coin.amount, - }, - confirmed_block_index: 1, - spent_block_index: 0, - spent: false, - coinbase: false, - timestamp: 0, - } -} - -/// Map a selected chia-query `CoinRecord` back to the native `Coin` it was built -/// from (identical parent/puzzle/amount ⇒ identical coin id). -fn from_record(record: &chia_query::CoinRecord) -> Result { - coin_record_to_protocol_coin(record) - .map_err(|e| ChainError::Chain(format!("coin selection: {e}"))) -} - /// Select XCH coins to cover `target` mojos, high-value-first, capped at `cap` coins /// (pass [`COIN_CAP`] for the default of 50). /// -/// Delegates to dig-l1-wallet's [`select_for_spend`] and translates the result into -/// digstore's [`XchSelection`]. Pure — no network, no signing. +/// Delegates to dig-wallet-backend's [`select_for_spend`] — which speaks in +/// `chia_protocol::Coin` natively — and re-expresses the result in digstore's +/// [`XchSelection`]. Pure — no network, no signing. pub fn select_xch(coins: &[Coin], target: u64, cap: usize) -> Result { - let records: Vec = coins.iter().map(to_record).collect(); - let outcome = select_for_spend(&records, target, "XCH", cap) - .map_err(|e| ChainError::Chain(format!("coin selection: {e}")))?; - Ok(match outcome { + Ok(match select_for_spend(coins, target, cap) { SelectionOutcome::Selected { - coins: selected, + coins, total, change, - .. - } => { - let coins = selected - .iter() - .map(from_record) - .collect::>>()?; - XchSelection::Selected { - coins, - total, - change, - } - } + } => XchSelection::Selected { + coins, + total, + change, + }, SelectionOutcome::NeedsConsolidation { available_coin_count, available_total, @@ -148,7 +114,6 @@ pub fn select_xch(coins: &[Coin], target: u64, cap: usize) -> Result XchSelection::InsufficientFunds { available_total, required, @@ -194,14 +159,12 @@ pub fn select_xch_coins(coins: &[Coin], target: u64) -> Result> { /// Select up to `cap` XCH coins to merge into a single coin during consolidation /// (highest-value first, deterministic). Requires at least 2 coins. /// -/// Delegates to dig-l1-wallet's [`select_for_consolidation`]. Pure — no network, no -/// signing. The returned coins feed the consolidation bundle builder +/// Delegates to dig-wallet-backend's [`select_for_consolidation`]. Pure — no network, +/// no signing. The returned coins feed the consolidation bundle builder /// ([`crate::send::build_xch_consolidation`]). pub fn select_xch_for_consolidation(coins: &[Coin], cap: usize) -> Result> { - let records: Vec = coins.iter().map(to_record).collect(); - let picked = select_for_consolidation(&records, cap) - .map_err(|e| ChainError::Chain(format!("consolidation selection: {e}")))?; - picked.iter().map(from_record).collect() + select_for_consolidation(coins, cap) + .map_err(|e| ChainError::Chain(format!("consolidation selection: {e}"))) } #[cfg(test)] @@ -227,6 +190,21 @@ mod tests { assert_eq!(COIN_CAP, 50); } + /// Regression guard for the epic #998 migration: digstore-chain must NOT depend on + /// the deprecated dig-l1-wallet — coin selection now comes from dig-wallet-backend. + #[test] + fn no_dig_l1_wallet_dependency() { + let manifest = include_str!("../Cargo.toml"); + assert!( + !manifest.contains("dig-l1-wallet"), + "digstore-chain must not depend on the deprecated dig-l1-wallet" + ); + assert!( + manifest.contains("dig-wallet-backend"), + "digstore-chain must depend on dig-wallet-backend" + ); + } + #[test] fn selects_high_value_first() { let coins = [coin(100, 1), coin(300, 2), coin(200, 3)]; diff --git a/deny.toml b/deny.toml index 2e863c4b..40aff45a 100644 --- a/deny.toml +++ b/deny.toml @@ -82,11 +82,6 @@ allow-git = [ "https://github.com/DIG-Network/dig-pex", "https://github.com/DIG-Network/dig-download", "https://github.com/DIG-Network/dig-peer-selector", - # dig-l1-wallet supplies the capped coin selector (`select_for_spend` / - # `select_for_consolidation`) the money commands front their bundle builders with - # (#410/#420). Its selection API lands at v0.3.0, which is not yet on crates.io (only - # v0.1.0 is), so it is pinned to the git tag until a crates.io v0.3.x ships (#216). - "https://github.com/DIG-Network/dig-l1-wallet", ] # Not currently gated in CI (see header). Kept for when license compliance is From 14c669df69f1d359b3bfa2ca84f7aeac94921c44 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Sat, 18 Jul 2026 17:29:11 -0700 Subject: [PATCH 3/3] =?UTF-8?q?docs(digstore-chain):=20SPEC=20=C2=A710.1?= =?UTF-8?q?=20dig-wallet-backend=20+=20COIN=5FCAP=20digstore-local=20(#100?= =?UTF-8?q?5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update SPEC.md coherence on §10.1 coin-management contract: - Replace stale dig-l1-wallet references with dig-wallet-backend's engine::selection primitive - Fix FACTUALLY WRONG claim that browser/JS uses COIN_CAP=50: digstore uses LOCAL COIN_CAP=50 (distinct from dig-wallet-backend's DEFAULT_COIN_CAP=500) for mempool cost tuning, NOT a shared cross-repo contract. JS layer doesn't pin a cap. This resolves the SPEC coherence blocker for feat/migrate-dig-wallet-backend. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01GtR1bZXpDNp2VFNJDtwsph --- SPEC.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/SPEC.md b/SPEC.md index 0540bc23..33b52097 100644 --- a/SPEC.md +++ b/SPEC.md @@ -254,7 +254,7 @@ The per-capsule price is **dynamic and USD-pegged**, NOT a fixed token amount: Scope note: a CLI/economic contract (not a `.dig` byte-format contract) governing how the money commands choose which XCH coins fund a spend, so a coin-fragmented wallet is never silently unable to publish. This is dig-store's expression of the ecosystem-wide **coin-management contract** -(`SYSTEM.md` → coin-management; the shared primitive is `dig-l1-wallet`). A `dig-store` +(`SYSTEM.md` → coin-management; the shared primitive is `dig-wallet-backend`'s engine seam `engine::selection`). A `dig-store` reimplementation MUST replicate it and MUST NOT hand-roll its own selection heuristic. Every XCH-funding spend built by `init` (mint fee), `commit` and `deploy` (root-advance XCH fee): @@ -264,8 +264,10 @@ Every XCH-funding spend built by `init` (mint fee), `commit` and `deploy` (root- taken greedily until the target (`fee` for a root advance, `fee + 1` for a mint) is met. This minimizes the number of inputs, keeping the bundle's CLVM cost well under Chia's per-block ceiling (§11.3). -- **Caps the attempt at 50 coins** (the shared `DEFAULT_COIN_CAP`; the boundary the browser/JS spend - layer uses too). Only the largest 50 coins are eligible for a single spend. +- **Caps the attempt at 50 coins** — digstore uses a LOCAL `COIN_CAP = 50`, distinct from + dig-wallet-backend's `DEFAULT_COIN_CAP = 500`, because digstore's spend bundles must stay under + Chia's mempool cost ceiling. Only the largest 50 coins are eligible for a single dig-store + XCH-funding spend. - **Distinguishes three outcomes** — never a flat failure that hides the counts: 1. **selectable** — the largest ≤ 50 coins cover the target; the bundle is built from exactly those. 2. **needs consolidation** — the wallet's TOTAL XCH covers the target, but the largest 50 coins do @@ -282,7 +284,7 @@ Every XCH-funding spend built by `init` (mint fee), `commit` and `deploy` (root- `NEEDS_CONSOLIDATION` error (exit 18) rather than spending unprompted. `--json` emits a `{"event":"consolidated", asset, merged_coins, merged_mojos, output_coin_id, tx_id}` record per round. -- **Never hand-rolls the selection or the merge** — both are the `dig-l1-wallet` primitives +- **Never hand-rolls the selection or the merge** — both are the `dig-wallet-backend` primitives (`select_for_spend` / `select_for_consolidation`); only the bundle construction (the datalayer_driver / `chia-wallet-sdk` builder) stays dig-store's.