feat: Dash Masternode List and Quorum Viewer#428
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughAdds Masternode List Diff UI and MnList backend tasks, implements a Core P2P handler, surfaces InstantLock/ChainLock items via ZMQ (rawchainlocksig), bumps Rust toolchain and dash-sdk, adjusts imports and private-key parsing, and flattens many nested conditionals across the codebase. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant UI as MasternodeListDiffScreen
participant App as AppContext
participant BT as BackendTask (MnList)
participant P2P as CoreP2PHandler
participant Core as Dash Core (P2P/ZMQ)
User->>UI: request masternode diff
UI->>App: dispatch BackendTask::MnListTask(...)
App->>BT: run_mnlist_task(task)
BT->>P2P: ensure handshake() / send request
P2P->>Core: P2P version/verack and GetMnListDiff/GetQRInfo
Core-->>P2P: response (mnlistdiff/qrinfo)
P2P-->>BT: decoded MnListDiff / QRInfo
BT-->>App: BackendTaskSuccessResult::MnListFetched*
App-->>UI: deliver result
UI-->>User: render diffs
note over Core,P2P: ZMQ publishes rawchainlocksig (Block + ChainLock)
Core-->>App: ZMQMessage::ChainLockedBlock(Block, ChainLock)
App-->>UI: forward as CoreItem::ChainLockedBlock
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
snap/snapcraft.yaml (1)
161-166: ImageMagick not installed but ‘convert’ is used.This will fail when the 256.png fallback path triggers.
build-packages: - build-essential - pkg-config @@ - xkb-data + - imagemagicksrc/ui/tokens/freeze_tokens_screen.rs (1)
559-567: Freeze button never opens the confirmation dialogClicking “Freeze” sets
self.confirmation_dialog = None, and the dialog is only shown whenis_some(). This prevents the flow from proceeding.Initialize the dialog on click (mirroring DestroyFrozenFunds):
- if ui.add(button).clicked() { - // Initialize confirmation dialog when button is clicked - self.confirmation_dialog = None; // Reset for fresh dialog - } + if ui.add(button).clicked() { + // Initialize confirmation dialog when button is clicked + let msg = format!( + "Are you sure you want to freeze identity {}?", + self.freeze_identity_id + ); + self.confirmation_dialog = Some( + ConfirmationDialog::new("Confirm Freeze", msg) + .confirm_text(Some("Confirm")) + .cancel_text(Some("Cancel")), + ); + }src/ui/wallets/import_wallet_screen.rs (1)
73-76: Avoid panic on key derivation; propagate error instead.Using expect(..) can crash the app. Return a user-facing Err so the UI can display it.
- let master_ecdsa_extended_private_key = - ExtendedPrivKey::new_master(self.app_context.network, &seed) - .expect("Failed to create master ECDSA extended private key"); + let master_ecdsa_extended_private_key = + ExtendedPrivKey::new_master(self.app_context.network, &seed) + .map_err(|e| format!("Failed to create master ECDSA extended private key: {e}"))?;
🧹 Nitpick comments (58)
src/ui/identities/identities_screen.rs (1)
199-207: Idiomatic, but consider a slimmer combinator form to avoid explicit branching.Functionally OK. For a tiny readability win, you could collapse to chained
and_then+cloned:- if let Some(master_identity_public_key) = qi.private_keys.find_master_key() - && let Some(wallet_derivation_path) = - &master_identity_public_key.in_wallet_at_derivation_path - && let Some(alias) = self - .wallet_seed_hash_cache - .get(&wallet_derivation_path.wallet_seed_hash) - { - return alias.clone(); - } - "".to_owned() + qi.private_keys + .find_master_key() + .and_then(|k| k.in_wallet_at_derivation_path.as_ref()) + .and_then(|p| self.wallet_seed_hash_cache.get(&p.wallet_seed_hash)) + .cloned() + .unwrap_or_default()CLAUDE.md (1)
59-59: Keep version wording consistent with toolchain (drop the “+”).Docs say “1.89+” while rust-toolchain pins 1.89. Suggest aligning to avoid confusion.
-1. **Rust**: Version 1.89+ (enforced by rust-toolchain.toml) +1. **Rust**: Version 1.89 (enforced by rust-toolchain.toml)rust-toolchain.toml (1)
2-2: Optionally include components in toolchain file for dev parity.Adding clippy/rustfmt here helps local devs match CI.
[toolchain] -channel = "1.89" +channel = "1.89" +components = ["clippy", "rustfmt"]snap/snapcraft.yaml (1)
52-55: Faster, reproducible Rust install.Use minimal profile and explicit install rather than setting default; keeps build env cleaner.
-# Install Rust -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.89 -export PATH="$HOME/.cargo/bin:$PATH" -rustc --version -cargo --version +# Install Rust (minimal) and pin toolchain +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal +export PATH="$HOME/.cargo/bin:$PATH" +rustup toolchain install 1.89 --profile minimal +rustup override set 1.89 +rustc --version +cargo --versionsrc/model/wallet/asset_lock_transaction.rs (1)
1-12: Replace magic SIGHASH constants; use Script builder for clarity.Improves readability and reduces footguns when forming scriptSig.
use dash_sdk::dpp::dashcore::{ Address, Network, OutPoint, PrivateKey, ScriptBuf, Transaction, TxIn, TxOut, }; +use dash_sdk::dpp::dashcore::script::Builder; +use dash_sdk::dpp::dashcore::sighash::EcdsaSighashType; @@ - let sighash_u32 = 1u32; + let sighash_type = EcdsaSighashType::All; @@ - .legacy_signature_hash(i, &script_pubkey, sighash_u32) + .legacy_signature_hash(i, &script_pubkey, sighash_type.to_u32()) .expect("expected sighash") @@ - // Serialize the DER-encoded signature and append the sighash type - let mut serialized_sig = sig.serialize_der().to_vec(); - - let mut sig_script = vec![serialized_sig.len() as u8 + 1]; - - sig_script.append(&mut serialized_sig); - - sig_script.push(1); - - let mut serialized_pub_key = private_key.public_key(&secp).serialize(); - - sig_script.push(serialized_pub_key.len() as u8); - sig_script.append(&mut serialized_pub_key); - // Create script_sig - input.script_sig = ScriptBuf::from_bytes(sig_script); + // Build scriptSig = <sig||sighash> <pubkey> + let mut sig_bytes = sig.serialize_der().to_vec(); + sig_bytes.push(sighash_type.to_u32() as u8); + let pubkey_bytes = private_key.public_key(&secp).serialize(); + input.script_sig = Builder::new() + .push_slice(&sig_bytes) + .push_slice(&pubkey_bytes) + .into_script();Also applies to: 165-165, 182-185, 221-221
.github/workflows/clippy.yml (2)
37-39: Toolchain bump LGTM; consider action update.actions-rs/toolchain is effectively archived. Consider dtolnay/rust-toolchain for maintenance longevity.
47-51: Align protoc with Snap (or vice versa).Unify versions to avoid subtle differences.
- curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v25.2/protoc-25.2-linux-x86_64.zip - sudo unzip -o protoc-25.2-linux-x86_64.zip -d /usr/local bin/protoc - sudo unzip -o protoc-25.2-linux-x86_64.zip -d /usr/local 'include/*' - rm -f protoc-25.2-linux-x86_64.zip + PROTOC_VERSION=31.1 + curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip + sudo unzip -o protoc-${PROTOC_VERSION}-linux-x86_64.zip -d /usr/local bin/protoc + sudo unzip -o protoc-${PROTOC_VERSION}-linux-x86_64.zip -d /usr/local 'include/*' + rm -f protoc-${PROTOC_VERSION}-linux-x86_64.zipsrc/database/wallet.rs (4)
386-388: Fix misleading error message ("32 bytes", not "64").- let wallet_seed_hash_array: [u8; 32] = - wallet_seed.try_into().expect("Seed should be 64 bytes"); + let wallet_seed_hash_array: [u8; 32] = + wallet_seed.try_into().expect("Seed hash should be 32 bytes");
340-356: Use unsigned DB types (and validate) for vout/value to avoid UB on negative data.- let vout: i64 = row.get(1)?; + let vout: u32 = row.get(1)?; ... - let value: i64 = row.get(3)?; + let value: u64 = row.get(3)?; ... - let outpoint = OutPoint { - txid: Txid::from_slice(&txid).expect("Invalid txid"), - vout: vout as u32, - }; + let outpoint = OutPoint { + txid: Txid::from_slice(&txid).expect("Invalid txid"), + vout, + }; - let tx_out = TxOut { - value: value as u64, - script_pubkey: ScriptBuf::from_bytes(script_pubkey), - }; + let tx_out = TxOut { + value, + script_pubkey: ScriptBuf::from_bytes(script_pubkey), + };
345-348: Validate UTXO addresses against the active network (don’t assume_checked).- let address = Address::from_str(&address) - .expect("Invalid address format") - .assume_checked(); + let address_unchecked = + Address::from_str(&address).expect("Invalid address format"); + let address = check_address_for_network(address_unchecked, network)?;
300-303: Don’t silently drop address-row errors; log them.- for row in address_rows { - if row.is_err() { - continue; - } + for row in address_rows { + if let Err(e) = &row { + tracing::warn!("skipping wallet address row due to error: {}", e); + continue; + }src/ui/wallets/wallets_screen/mod.rs (2)
456-467: Header label/sort mismatch: this column is Balance, not Total Received.- let label = if self.sort_column == SortColumn::Balance { - match self.sort_order { - SortOrder::Ascending => "Total Received (DASH) ^", - SortOrder::Descending => "Total Received (DASH) v", - } - } else { - "Total Received (DASH)" - }; + let label = if self.sort_column == SortColumn::Balance { + match self.sort_order { + SortOrder::Ascending => "Balance (DASH) ^", + SortOrder::Descending => "Balance (DASH) v", + } + } else { + "Balance (DASH)" + };
482-493: Header label/sort mismatch: this column is Total Received, not Balance.- let label = if self.sort_column == SortColumn::TotalReceived { - match self.sort_order { - SortOrder::Ascending => "Balance (DASH) ^", - SortOrder::Descending => "Balance (DASH) v", - } - } else { - "Balance (DASH)" - }; + let label = if self.sort_column == SortColumn::TotalReceived { + match self.sort_order { + SortOrder::Ascending => "Total Received (DASH) ^", + SortOrder::Descending => "Total Received (DASH) v", + } + } else { + "Total Received (DASH)" + };src/ui/tokens/add_token_by_id_screen.rs (1)
131-156: Guarded “Add Token” action is correct; consider always showing a disabled button.Optional UX: render a disabled “Add Token” button until both a contract and token are selected, so the CTA doesn’t pop in/out.
- if let (Some(contract), Some(tok)) = (&self.fetched_contract, &self.selected_token) + if let (Some(contract), Some(tok)) = (&self.fetched_contract, &self.selected_token) && ui .add( egui::Button::new(RichText::new("Add Token").color(Color32::WHITE)) .fill(Color32::from_rgb(0, 120, 0)), ) .clicked() { ... } + else { + // Keep CTA visible but disabled until prerequisites are met + let _ = ui.add_enabled( + false, + egui::Button::new(RichText::new("Add Token").color(Color32::WHITE)) + .fill(Color32::from_rgb(0, 120, 0)), + ); + }src/ui/components/identity_selector.rs (1)
191-200: Good simplification; avoid extra work and keep behavior.Minor: the doc comment says this will panic if no identities and no “Other”; current code does not. Align the doc or enforce the panic.
src/backend_task/tokens/claim_tokens.rs (1)
76-83: Use tracing over eprintln! and deduplicate the two nearly identical branches.- eprintln!("Failed to update token balance from claim document: {}", e); + tracing::warn!("failed to update token balance from claim document: {}", e); ... - eprintln!( - "Failed to update token balance from group action document: {}", - e - ); + tracing::warn!( + "failed to update token balance from group action document: {}", + e + );You can also extract a small helper to parse (claimerId, amount) and perform the balance insert, then call it from both arms.
Also applies to: 90-99
src/ui/tokens/pause_tokens_screen.rs (2)
92-112: Wrong action text (“burn”) in Pause screen; replace with “pause”.- error_message = Some("Burning is not allowed on this token".to_string()); + error_message = Some("Pausing is not allowed on this token".to_string()); ... - error_message = Some( - "You are not allowed to burn this token. Only the contract owner is." - .to_string(), - ); + error_message = Some( + "You are not allowed to pause this token. Only the contract owner is." + .to_string(), + ); ... - error_message = Some("You are not allowed to burn this token".to_string()); + error_message = Some("You are not allowed to pause this token".to_string());
153-165: Avoid redundant check and clone; borrow the group instead.- if group.is_some() - && let Some((_, group)) = group.clone() - { - let your_power = group - .members() - .get(&identity_token_info.identity.identity.id()); - - if let Some(your_power) = your_power - && your_power >= &group.required_power() - { - is_unilateral_group_member = true; - } - }; + if let Some((_, group)) = group.as_ref() { + if group + .members() + .get(&identity_token_info.identity.identity.id()) + .is_some_and(|p| p >= &group.required_power()) + { + is_unilateral_group_member = true; + } + }src/ui/tokens/set_token_price_screen.rs (2)
175-186: Avoid cloning Group; borrow insteadClone is unnecessary; borrow via pattern match to reduce allocations.
Apply:
- if group.is_some() - && let Some((_, group)) = group.clone() - { - let your_power = group - .members() - .get(&identity_token_info.identity.identity.id()); - - if let Some(your_power) = your_power - && your_power >= &group.required_power() - { - is_unilateral_group_member = true; - } - }; + if let Some((_, ref group)) = group { + if let Some(your_power) = + group.members().get(&identity_token_info.identity.identity.id()) + && your_power >= &group.required_power() + { + is_unilateral_group_member = true; + } + }
88-91: Round when converting Dash→credits to avoid silent truncationCasting f64 to integer truncates; round first to represent intended credits.
Apply:
- fn dash_to_credits(dash_amount: f64) -> Credits { - (dash_amount * 100_000_000_000.0) as Credits - } + fn dash_to_credits(dash_amount: f64) -> Credits { + (dash_amount * 100_000_000_000.0).round() as Credits + }src/ui/tokens/resume_tokens_screen.rs (1)
152-164: Avoid cloning Group; borrow insteadSame clone pattern as elsewhere; borrow via &group.
Apply:
- if group.is_some() - && let Some((_, group)) = group.clone() - { - let your_power = group - .members() - .get(&identity_token_info.identity.identity.id()); - - if let Some(your_power) = your_power - && your_power >= &group.required_power() - { - is_unilateral_group_member = true; - } - }; + if let Some((_, ref group)) = group { + if let Some(your_power) = + group.members().get(&identity_token_info.identity.identity.id()) + && your_power >= &group.required_power() + { + is_unilateral_group_member = true; + } + }src/ui/tokens/burn_tokens_screen.rs (2)
172-184: Avoid cloning Group; borrow insteadSame improvement as other screens.
Apply:
- if group.is_some() - && let Some((_, group)) = group.clone() - { - let your_power = group - .members() - .get(&identity_token_info.identity.identity.id()); - - if let Some(your_power) = your_power - && your_power >= &group.required_power() - { - is_unilateral_group_member = true; - } - }; + if let Some((_, ref group)) = group { + if let Some(your_power) = + group.members().get(&identity_token_info.identity.identity.id()) + && your_power >= &group.required_power() + { + is_unilateral_group_member = true; + } + }
439-451: Key availability check inconsistent with TokenAction filteringHere you check any auth key exists; TokenAction later filters to CRITICAL. Align this to avoid UX mismatch.
Apply:
- } else { - !self - .identity_token_info - .identity - .available_authentication_keys() - .is_empty() - }; + } else { + !self + .identity_token_info + .identity + .available_authentication_keys_with_critical_security_level() + .is_empty() + };src/ui/tokens/mint_tokens_screen.rs (2)
165-177: Avoid cloning Group; borrow insteadSame change as other screens.
Apply:
- if group.is_some() - && let Some((_, group)) = group.clone() - { - let your_power = group - .members() - .get(&identity_token_info.identity.identity.id()); - - if let Some(your_power) = your_power - && your_power >= &group.required_power() - { - is_unilateral_group_member = true; - } - }; + if let Some((_, ref group)) = group { + if let Some(your_power) = + group.members().get(&identity_token_info.identity.identity.id()) + && your_power >= &group.required_power() + { + is_unilateral_group_member = true; + } + }
82-87: Reduce duplication: extract “unilateral group member” checkThis pattern repeats across token screens. Consider a small helper (e.g., in ui::helpers) to compute unilateral membership given (&Group, &Identifier).
Example (outside this file):
pub fn is_unilateral_member(group: &Group, who: &Identifier) -> bool { group .members() .get(who) .map(|p| *p >= group.required_power()) .unwrap_or(false) }src/ui/tokens/unfreeze_tokens_screen.rs (1)
167-179: Avoid cloning Group; borrow insteadSame improvement as elsewhere.
Apply:
- if group.is_some() - && let Some((_, group)) = group.clone() - { - let your_power = group - .members() - .get(&identity_token_info.identity.identity.id()); - - if let Some(your_power) = your_power - && your_power >= &group.required_power() - { - is_unilateral_group_member = true; - } - }; + if let Some((_, ref group)) = group { + if let Some(your_power) = + group.members().get(&identity_token_info.identity.identity.id()) + && your_power >= &group.required_power() + { + is_unilateral_group_member = true; + } + }src/ui/components/amount_input.rs (2)
265-273: Avoid mixed let-chain with boolean; prefer clearer guard to keep MSRV-safe and readableThis mixed pattern is harder to parse and may be brittle across compiler versions. A simple guard or match keeps it clear and gives you
max_amountfor formatting without extra gymnastics.Apply:
- // Check if amount exceeds maximum - if let Some(max_amount) = self.max_amount - && amount.value() > max_amount - { - return Err(format!( - "Amount {} exceeds allowed maximum {}", - amount, - Amount::new(max_amount, self.decimal_places) - )); - } + // Check if amount exceeds maximum + if let Some(max_amount) = self.max_amount { + if amount.value() > max_amount { + return Err(format!( + "Amount {} exceeds allowed maximum {}", + amount, + Amount::new(max_amount, self.decimal_places) + )); + } + }If you prefer an expression form,
if let Some(m) = self.max_amount { ... }ormatch self.max_amount { Some(m) if amount.value() > m => ... , _ => {} }keeps it idiomatic. Please confirm this compiles cleanly on Rust 1.89 in CI.
276-283: Same here: simplify the min checkMirror the approach used for max to avoid mixed let-chain + boolean.
- // Check if amount is below minimum - if let Some(min_amount) = self.min_amount - && amount.value() < min_amount - { - return Err(format!( - "Amount must be at least {}", - Amount::new(min_amount, self.decimal_places) - )); - } + // Check if amount is below minimum + if let Some(min_amount) = self.min_amount { + if amount.value() < min_amount { + return Err(format!( + "Amount must be at least {}", + Amount::new(min_amount, self.decimal_places) + )); + } + }src/ui/tokens/destroy_frozen_funds_screen.rs (1)
171-183: Remove redundant is_some + clone; borrow instead
group.is_some()is redundant with the followinglet Some, and cloninggroupcopies the whole structure. Borrow it and useOption::is_some_andfor the power check.- if group.is_some() - && let Some((_, group)) = group.clone() - { - let your_power = group - .members() - .get(&identity_token_info.identity.identity.id()); - - if let Some(your_power) = your_power - && your_power >= &group.required_power() - { - is_unilateral_group_member = true; - } - }; + if let Some((_, group)) = &group { + let your_power = group.members().get(&identity_token_info.identity.identity.id()); + if your_power.is_some_and(|p| p >= &group.required_power()) { + is_unilateral_group_member = true; + } + };src/backend_task/tokens/transfer_tokens.rs (2)
102-115: De-duplicate document parsing and prefer structured loggingBoth branches parse the same four fields; factor into a helper to reduce duplication and switch
eprintln!totracing::warn!for consistency with the rest of the codebase.- if let ( + if let ( Some(sender_value), Some(sender_amount_value), Some(recipient_value), Some(recipient_amount_value), ) = ( document.get("senderId"), document.get("senderAmount"), document.get("recipientId"), document.get("recipientAmount"), - ) && let ( + ) && let ( Value::Identifier(sender_bytes), Value::U64(sender_amount), Value::Identifier(recipient_bytes), Value::U64(recipient_amount), - ) = ( + ) = ( sender_value, sender_amount_value, recipient_value, recipient_amount_value, - ) && let (Ok(sender_id), Ok(recipient_id)) = ( + ) && let (Ok(sender_id), Ok(recipient_id)) = ( Identifier::from_bytes(sender_bytes), Identifier::from_bytes(recipient_bytes), ) { - if let Err(e) = self.insert_token_identity_balance( - &token_id, - &sender_id, - *sender_amount, - ) { - eprintln!( - "Failed to update sender token balance from historical document: {}", - e - ); - } - if let Err(e) = self.insert_token_identity_balance( - &token_id, - &recipient_id, - *recipient_amount, - ) { - eprintln!( - "Failed to update recipient token balance from historical document: {}", - e - ); - } + Self::update_balances_from_doc(self, &token_id, &sender_id, *sender_amount, &recipient_id, *recipient_amount); }Add once (outside this hunk):
fn update_balances_from_doc( &self, token_id: &Identifier, sender_id: &Identifier, sender_amount: u64, recipient_id: &Identifier, recipient_amount: u64, ) { if let Err(e) = self.insert_token_identity_balance(token_id, sender_id, sender_amount) { tracing::warn!("Failed to update sender token balance from document: {e}"); } if let Err(e) = self.insert_token_identity_balance(token_id, recipient_id, recipient_amount) { tracing::warn!("Failed to update recipient token balance from document: {e}"); } }Also applies to: 116-136
151-164: Same duplication in GroupActionWithDocument branchApply the same helper to keep both paths in sync.
Also applies to: 165-185
src/ui/components/contract_chooser_panel.rs (1)
543-603: Use actual window rect instead of an approximate size to close on outside clicksHard-coding 150x70 can mis-detect inside vs. outside clicks on different DPIs/content. Capture the window response rect and use it for hit-testing.
- if let Some(contract) = contract_opt { - egui::Window::new("Contract Menu") + if let Some(contract) = contract_opt { + let window_resp = egui::Window::new("Contract Menu") .id(egui::Id::new("contract_context_menu")) .title_bar(false) .resizable(false) .collapsible(false) .fixed_pos(chooser_state.context_menu_position) - .show(ctx, |ui| { + .show(ctx, |ui| { ui.set_min_width(150.0); // ... }); - - // Close menu if clicked elsewhere - if ctx.input(|i| i.pointer.any_click()) { - // Check if click was outside the menu - let menu_rect = egui::Rect::from_min_size( - chooser_state.context_menu_position, - egui::vec2(150.0, 70.0), // Approximate size - ); - if let Some(pointer_pos) = ctx.pointer_interact_pos() - && !menu_rect.contains(pointer_pos) - { - chooser_state.show_context_menu = false; - } - } + if ctx.input(|i| i.pointer.any_click()) { + if let Some(resp) = window_resp { + if let Some(pointer_pos) = ctx.pointer_interact_pos() { + if !resp.response.rect.contains(pointer_pos) { + chooser_state.show_context_menu = false; + } + } + } else { + chooser_state.show_context_menu = false; + } + } }src/ui/tokens/update_token_config.rs (1)
210-214: Minor readability: use is_some_and or borrow to avoid extra bindingKeep the style consistent while avoiding a temporary name that shadows meaning.
- if let Some(your_power) = your_power - && your_power >= &group.required_power() - { + if your_power.is_some_and(|p| p >= &group.required_power()) { self.is_unilateral_group_member = true; }src/ui/tokens/freeze_tokens_screen.rs (1)
163-175: Same group check nit: remove redundant is_some + clone; borrow + is_some_andAvoid cloning the group and prefer a direct borrow for the power check.
- if group.is_some() - && let Some((_, group)) = group.clone() - { - let your_power = group - .members() - .get(&identity_token_info.identity.identity.id()); - - if let Some(your_power) = your_power - && your_power >= &group.required_power() - { - is_unilateral_group_member = true; - } - }; + if let Some((_, group)) = &group { + let your_power = group.members().get(&identity_token_info.identity.identity.id()); + if your_power.is_some_and(|p| p >= &group.required_power()) { + is_unilateral_group_member = true; + } + };Cargo.toml (1)
7-7: MSRV bump to 1.89 — pin CI toolchainsrust-toolchain.toml, Cargo.toml, CLAUDE.md and snap/snapcraft.yaml are set to 1.89 and .github/workflows/clippy.yml is pinned to 1.89. .github/workflows/tests.yml:37 and .github/workflows/release.yml:75 still use "stable" — change those to "1.89" or confirm you intend to track rolling "stable".
src/ui/wallets/import_wallet_screen.rs (2)
81-87: Name the intermediate xprv and xpub distinctly.Variable holds an xprv, then later becomes an xpub, which is confusing. Prefer separate names (e.g., account0_xprv, account0_xpub) for clarity. No behavior change.
266-268: Let‑chains cleanup is good; consider avoiding substring error checks.The guard style is clear. Consider matching a structured error enum instead of error_msg.contains("Invalid seed phrase").
Also applies to: 279-283, 286-288
src/backend_task/core/mod.rs (1)
45-46: New CoreItem variants are sensible; reduce tuple noise with a type alias.Define a small alias to avoid repeating (OutPoint, TxOut, Address).
+type ResolvedInput = (OutPoint, TxOut, Address); pub enum CoreItem { - InstantLockedTransaction(Transaction, Vec<(OutPoint, TxOut, Address)>, InstantLock), - ... - ChainLockedBlock(Block, ChainLock), + InstantLockedTransaction(Transaction, Vec<ResolvedInput>, InstantLock), + ... + ChainLockedBlock(Block, ChainLock), }Also applies to: 54-55
src/ui/tokens/tokens_screen/distributions.rs (2)
381-416: Use saturating_mul to avoid u64 overflow in display math.Large inputs could overflow when multiplying interval × step count.
- let amount = - perpetual_dist_interval_input * step_count_input; + let amount = + perpetual_dist_interval_input.saturating_mul(step_count_input);
521-592: Same here: prefer saturating_mul for step position math.Protects text computation from overflow.
- let block = step_position * perpetual_dist_interval_input; + let block = step_position.saturating_mul(perpetual_dist_interval_input); ... - let time = step_position * perpetual_dist_interval_input; + let time = step_position.saturating_mul(perpetual_dist_interval_input); ... - let epoch = step_position * perpetual_dist_interval_input; + let epoch = step_position.saturating_mul(perpetual_dist_interval_input);src/ui/network_chooser_screen.rs (1)
609-636: Save Password flow: nice chained guard + in‑memory reinit.Consider surfacing failures to the user (toast/message) instead of only eprintln!.
src/components/core_p2p_handler.rs (5)
19-24: Consider making port private.The
portandstreamfields should be private as they're implementation details. Onlynetworkneeds to be public.#[derive(Debug)] pub struct CoreP2PHandler { pub network: Network, - pub port: u16, - pub stream: TcpStream, - pub handshake_success: bool, + port: u16, + stream: TcpStream, + handshake_success: bool, }
53-53: Replace println! with proper logging.Debug output should use a proper logging framework instead of
println!.- println!("Connected to Dash Core at 127.0.0.1:{}", port); + tracing::info!("Connected to Dash Core at 127.0.0.1:{}", port);Apply similar changes to all other
println!calls.Also applies to: 78-78, 134-134, 218-218, 323-323
91-97: Remove commented debug code.Commented-out debug code should be removed from production code.
Remove the commented blocks for writing to DML.DAT and QR_INFO.DAT files.
Also applies to: 146-152
201-201: Typo in random number generation method.The method name has a typo:
r#genshould begen.- nonce: rng.r#gen(), + nonce: rng.gen(),
206-206: Typo in random number generation method.Same typo as above.
- mn_auth_challenge: rng.r#gen(), + mn_auth_challenge: rng.gen(),src/ui/contracts_documents/document_action_screen.rs (1)
382-387: Let‑chain refactor is correct and clearerThe combined guard cleanly replaces the nested condition with identical behavior.
Consider centralizing the magic string into a constant to avoid future drift across files.
src/ui/tokens/direct_token_purchase_screen.rs (1)
305-305: Fix user‑facing typo: “purchaseed” → “purchased”Minor but visible issue in success detection.
Apply:
- if message.contains("Successfully purchaseed tokens") || message == "PurchaseTokens" + if message.contains("Successfully purchased tokens") || message == "PurchaseTokens"src/backend_task/identity/mod.rs (1)
141-151: Avoid panics on unsupported key types in identity key mappingUsing
panic!in non-test code can crash the app; prefer graceful handling or error propagation.Consider returning
Result<_, Error>from these helpers (or skipping unknown types with logging) instead ofpanic!("need a ECDSA Key for now").Also applies to: 166-176
src/ui/components/tools_subscreen_chooser_panel.rs (1)
127-161: Consider extracting screen navigation to reduce duplicationThe match statement for screen navigation has become quite verbose. Consider extracting the pattern into a helper function or using a mapping approach.
Consider refactoring the repetitive navigation pattern:
- match subscreen { - ToolsSubscreen::ProofLog => { - action = AppAction::SetMainScreen( - RootScreenType::RootScreenToolsProofLogScreen, - ) - } - // ... many similar cases - } + action = AppAction::SetMainScreen(subscreen.to_root_screen_type());And add a method to the enum:
impl ToolsSubscreen { pub fn to_root_screen_type(&self) -> RootScreenType { match self { Self::ProofLog => RootScreenType::RootScreenToolsProofLogScreen, Self::TransactionViewer => RootScreenType::RootScreenToolsTransitionVisualizerScreen, // ... etc } } }src/components/core_zmq_listener.rs (1)
150-171: Error message incorrectly refers to InstantLock instead of ChainLock.The error message on line 167 says "Error deserializing InstantLock" but should say "Error deserializing ChainLock".
Apply this diff to fix the error message:
- eprintln!( - "Error deserializing InstantLock: {}", - e - ); + eprintln!( + "Error deserializing ChainLock: {}", + e + );src/backend_task/mnlist.rs (3)
50-51: Consider connection reuse for P2P handler.Multiple
CoreP2PHandler::new()instances are created across different task branches. Consider creating a single P2P handler at the function level and reusing it, or implementing a connection pool for better resource management.Apply this refactor to reduce connection overhead:
pub async fn run_mnlist_task( app: &AppContext, task: MnListTask, ) -> Result<BackendTaskSuccessResult, String> { + let network = app.network; + let mut p2p = match task { + MnListTask::FetchEndDmlDiff { .. } + | MnListTask::FetchEndQrInfo { .. } + | MnListTask::FetchEndQrInfoWithDmls { .. } + | MnListTask::FetchDiffsChain { .. } => Some(CoreP2PHandler::new(network, None)?), + _ => None, + }; + match task { MnListTask::FetchEndDmlDiff { base_block_height, base_block_hash, block_height, block_hash, validate_quorums: _, } => { - let network = app.network; - let mut p2p = CoreP2PHandler::new(network, None)?; + let p2p = p2p.as_mut().unwrap(); let diff = p2p.get_dml_diff(base_block_hash, block_hash)?;
100-100: Consider adding error context for block hash conversion.The conversion from RPC hash to DPP hash could benefit from error context if this operation can fail.
47-47: Unused parametervalidate_quorums.The
validate_quorumsparameter inFetchEndDmlDiffis received but not used (marked with_). Consider removing it if not needed or implementing the validation logic if it's intended for future use.src/backend_task/identity/load_identity.rs (1)
133-134: Consider more specific error message for missing voter identity.The error message "Voter Identity not found" could include the voter identifier for better debugging.
- Ok(None) => return Err("Voter Identity not found".to_string()), + Ok(None) => return Err(format!("Voter Identity not found for identifier: {}", voter_identifier)),src/app.rs (3)
247-321: Reduce per‑network screen re-instantiationYou re-create MasternodeListDiffScreen for each network branch. Consider extracting a small helper to build tool screens for a given AppContext to cut duplication and drift.
If you prefer a minimal change: construct once, then immediately retarget via a context-aware init method (if available on the screen), instead of full re-instantiation in each branch.
623-627: Handle poisoned mutex on ZMQ status updateCurrent let-chain ignores lock poisoning; recover and log to avoid silent staleness.
Apply:
- if let Ok(event) = self.current_app_context().rx_zmq_status.try_recv() - && let Ok(mut status) = self.current_app_context().zmq_connection_status.lock() - { - *status = event; - } + if let Ok(event) = self.current_app_context().rx_zmq_status.try_recv() { + match self.current_app_context().zmq_connection_status.lock() { + Ok(mut status) => *status = event, + Err(poisoned) => { + *poisoned.into_inner() = event; + tracing::warn!("ZMQ status mutex poisoned; recovered"); + } + } + }
711-719: Avoid cloning txNo further use of tx after the DB call; you can move it and drop the clone.
Apply:
- CoreItem::InstantLockedTransaction(tx.clone(), utxos, is_lock); + CoreItem::InstantLockedTransaction(tx, utxos, is_lock);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
Cargo.lockis excluded by!**/*.lockartifacts/mn_list_diff_0_2227096.binis excluded by!**/*.binartifacts/mn_list_diff_testnet_0_1296600.binis excluded by!**/*.bin
📒 Files selected for processing (64)
.github/workflows/clippy.yml(1 hunks)CLAUDE.md(1 hunks)Cargo.toml(3 hunks)dash_core_configs/mainnet.conf(1 hunks)rust-toolchain.toml(1 hunks)snap/snapcraft.yaml(1 hunks)src/app.rs(10 hunks)src/backend_task/core/mod.rs(3 hunks)src/backend_task/identity/load_identity.rs(4 hunks)src/backend_task/identity/load_identity_from_wallet.rs(1 hunks)src/backend_task/identity/mod.rs(1 hunks)src/backend_task/mnlist.rs(1 hunks)src/backend_task/mod.rs(4 hunks)src/backend_task/tokens/burn_tokens.rs(1 hunks)src/backend_task/tokens/claim_tokens.rs(1 hunks)src/backend_task/tokens/mint_tokens.rs(1 hunks)src/backend_task/tokens/query_tokens.rs(1 hunks)src/backend_task/tokens/set_token_price.rs(1 hunks)src/backend_task/tokens/transfer_tokens.rs(2 hunks)src/components/core_p2p_handler.rs(1 hunks)src/components/core_zmq_listener.rs(4 hunks)src/components/mod.rs(1 hunks)src/context.rs(1 hunks)src/database/contracts.rs(1 hunks)src/database/wallet.rs(1 hunks)src/model/qualified_identity/encrypted_key_storage.rs(1 hunks)src/model/qualified_identity/mod.rs(1 hunks)src/model/wallet/asset_lock_transaction.rs(1 hunks)src/model/wallet/mod.rs(2 hunks)src/ui/components/amount_input.rs(1 hunks)src/ui/components/contract_chooser_panel.rs(1 hunks)src/ui/components/identity_selector.rs(1 hunks)src/ui/components/tools_subscreen_chooser_panel.rs(5 hunks)src/ui/contracts_documents/contracts_documents_screen.rs(2 hunks)src/ui/contracts_documents/document_action_screen.rs(1 hunks)src/ui/contracts_documents/group_actions_screen.rs(1 hunks)src/ui/contracts_documents/register_contract_screen.rs(1 hunks)src/ui/contracts_documents/update_contract_screen.rs(1 hunks)src/ui/dpns/dpns_contested_names_screen.rs(3 hunks)src/ui/helpers.rs(1 hunks)src/ui/identities/add_new_identity_screen/mod.rs(2 hunks)src/ui/identities/identities_screen.rs(5 hunks)src/ui/identities/top_up_identity_screen/mod.rs(2 hunks)src/ui/mod.rs(16 hunks)src/ui/network_chooser_screen.rs(2 hunks)src/ui/tokens/add_token_by_id_screen.rs(1 hunks)src/ui/tokens/burn_tokens_screen.rs(2 hunks)src/ui/tokens/claim_tokens_screen.rs(1 hunks)src/ui/tokens/destroy_frozen_funds_screen.rs(2 hunks)src/ui/tokens/direct_token_purchase_screen.rs(1 hunks)src/ui/tokens/freeze_tokens_screen.rs(2 hunks)src/ui/tokens/mint_tokens_screen.rs(2 hunks)src/ui/tokens/pause_tokens_screen.rs(2 hunks)src/ui/tokens/resume_tokens_screen.rs(2 hunks)src/ui/tokens/set_token_price_screen.rs(2 hunks)src/ui/tokens/tokens_screen/distributions.rs(2 hunks)src/ui/tokens/tokens_screen/mod.rs(4 hunks)src/ui/tokens/unfreeze_tokens_screen.rs(2 hunks)src/ui/tokens/update_token_config.rs(3 hunks)src/ui/tools/mod.rs(1 hunks)src/ui/tools/transition_visualizer_screen.rs(2 hunks)src/ui/wallets/add_new_wallet_screen.rs(1 hunks)src/ui/wallets/import_wallet_screen.rs(3 hunks)src/ui/wallets/wallets_screen/mod.rs(2 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-07-23T14:07:31.895Z
Learnt from: CR
PR: dashpay/dash-evo-tool#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-23T14:07:31.895Z
Learning: Applies to components/**/*.rs : Shared components, including ZMQ core listeners, should be placed in the `components/` directory.
Applied to files:
src/components/mod.rs
📚 Learning: 2025-07-23T14:07:31.895Z
Learnt from: CR
PR: dashpay/dash-evo-tool#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-23T14:07:31.895Z
Learning: Applies to model/**/*.rs : Data structures, including qualified identities with encrypted key storage, should be defined in the `model/` directory.
Applied to files:
src/model/qualified_identity/encrypted_key_storage.rs
📚 Learning: 2025-07-23T14:07:31.895Z
Learnt from: CR
PR: dashpay/dash-evo-tool#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-23T14:07:31.895Z
Learning: Applies to src/app.rs : Screen transitions should update the screen stack in `app.rs`.
Applied to files:
src/ui/mod.rs
📚 Learning: 2024-11-18T14:40:33.353Z
Learnt from: ogabrielides
PR: dashpay/dash-evo-tool#73
File: src/backend_task/core/start_dash_qt.rs:17-18
Timestamp: 2024-11-18T14:40:33.353Z
Learning: In `src/backend_task/core/start_dash_qt.rs`, the `start_dash_qt` function verifies the existence of `dash_qt_path` using `dash_qt_path.exists()`, which the team considers sufficient validation for `custom_dash_qt` provided by the user.
Applied to files:
src/ui/network_chooser_screen.rs
|
|
||
| match topic { | ||
| "rawchainlock" => { | ||
| "rawchainlocksig" => { |
There was a problem hiding this comment.
Topic mismatch: subscribing to "rawchainlock" but matching "rawchainlocksig".
The subscription on line 105 is for "rawchainlock" (via CHAIN_LOCKED_BLOCK_MSG), but the topic match is for "rawchainlocksig". This appears to be a disconnect between subscription and processing.
Apply this diff to align the topic with the subscription:
- "rawchainlocksig" => {
+ "rawchainlock" => {Alternatively, if the intent is to subscribe to "rawchainlocksig", update the subscription constant:
-pub const CHAIN_LOCKED_BLOCK_MSG: &[u8; 12] = b"rawchainlock";
+pub const CHAIN_LOCKED_BLOCK_MSG: &[u8; 15] = b"rawchainlocksig";And update the subscription call:
- .set_subscribe(CHAIN_LOCKED_BLOCK_MSG)
- .expect("Failed to subscribe to rawchainlock");
+ .set_subscribe(CHAIN_LOCKED_BLOCK_MSG)
+ .expect("Failed to subscribe to rawchainlocksig");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "rawchainlocksig" => { | |
| "rawchainlock" => { |
🤖 Prompt for AI Agents
In src/components/core_zmq_listener.rs around lines 105 and 140, the ZMQ
subscription constant and the match arm topic are inconsistent: the code
subscribes to CHAIN_LOCKED_BLOCK_MSG ("rawchainlock") but the match arm checks
"rawchainlocksig". Fix by making both sides use the same topic: either change
the match arm at line 140 to "rawchainlock" to process messages for the existing
CHAIN_LOCKED_BLOCK_MSG subscription, or if the intended topic is
"rawchainlocksig", update the CHAIN_LOCKED_BLOCK_MSG constant to
"rawchainlocksig" and change the subscription call to use the new constant so
the subscribed topic and match arm align.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
src/components/core_p2p_handler.rs (1)
50-57: Kudos for adding connect timeout and loop timeouts.These address prior review notes about indefinite waits.
Also applies to: 85-99, 145-159, 327-341
🧹 Nitpick comments (5)
src/components/core_p2p_handler.rs (5)
19-24: Encapsulate internals: make stream and handshake_success private.Exposing TcpStream and handshake_success breaks invariants (callers could read/write or flip the flag). Keep API surface small.
pub struct CoreP2PHandler { pub network: Network, pub port: u16, - pub stream: TcpStream, - pub handshake_success: bool, + stream: TcpStream, + handshake_success: bool, }If external visibility is required, expose read-only accessors.
235-236: Remove fixed sleep; rely on I/O timeouts instead.The 50 ms delay adds latency and is brittle.
- thread::sleep(Duration::from_millis(50));
370-372: Docstring mismatch.The comment says GetMnListDiff but the method is get_qr_info.
- /// Sends a `GetMnListDiff` request after completing the handshake. + /// Sends a `GetQRInfo` request after completing the handshake.
201-222: Use rng.gen(), not raw identifier r#gen().r#gen is unnecessary and non-idiomatic here.
- nonce: rng.r#gen(), + nonce: rng.gen(), user_agent: "/dash-evo-tool:0.9/".to_string(), start_height: 0, relay: false, - mn_auth_challenge: rng.r#gen(), + mn_auth_challenge: rng.gen(),
66-124: Deduplicate request/response plumbing.send_dml_request_message and send_qr_info_request_message are nearly identical. Consider a single helper parametric over expected command and response variant to reduce drift.
If helpful, I can draft a generic helper that takes (NetworkMessage, expected_cmd: &str) and a closure to extract the variant from RawNetworkMessage.
Also applies to: 126-194
|
When fetching rotated MN list diffs I get "Required rotated chain lock sig at h - 3 not present for masternode diff block hash" |
* fix: top up with qr code wasnt working (#410) * fix: top up with qr code wasnt working * fmt and clippy * coderabbit * fix: dash-qt path autodetection fails (#409) * fix: dash-qt path not detected correctly * fix: correct handling of dash-qt path clear button * chore: copilot review * fix: change of wallet on top up does not update the address (#414) * build(deps): upgrade build dependencies (egui 0.32.0, rusqlite 0.37, and others) (#406) * build(deps): update all rust dependencies * chore: replace depreacated ui.close_menu() * chore: upgrade Popup in identities screen * fix: actions menu items width too low * chore: all warnings fixed * chore: close identity actions on click outside --------- Co-authored-by: pauldelucia <pauldelucia2@gmail.com> * refactor: unified identity selector (#408) * refactor: unified identity selection * feat: identity selector implementation on multiple screens * feat: add label to IdentitySelector * chore: I think final * Update src/ui/components/identity_selector.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: settings are read from db 20 times a second (#420) * feat: wallet unlock on wallet screen (#415) * refactor: Amount type and AmountInput component (#417) * feat: amount input, first building version * test(amount): fixed tests * chore: I think final * chore: my_tokens display correct amount * chore: transfer tokens update * chore: hide unit on rewards estimate column * chore: two new helper methods * chore: I think finals * cargo fmt * feat: component trait * impl Component for AmountInput * chore: updated component trait * chore: update for egui enabled state mgmt * doc: component design pattern doc * chore: component design pattern continued * chore: amount improvements * chore: copilot review * chore: amount improvements * backport: amount component from * chore: fix imports * chore: refactor * chore: futher refactor * chore: further refactor based on feedback * doc: simplified component design pattern description * chore: peer review * doc: update docs * chore: amount input * test: run tests using github actions and fix failing tests (#422) * fix: failing tests * gha: run tests * fix: tests fail due to lack of .env file * fix: incorrect decimals handling on token create, mint and burn screens (#419) * feat: amount input, first building version * test(amount): fixed tests * chore: I think final * chore: my_tokens display correct amount * chore: transfer tokens update * chore: hide unit on rewards estimate column * chore: two new helper methods * chore: I think finals * cargo fmt * feat: component trait * impl Component for AmountInput * chore: updated component trait * chore: update for egui enabled state mgmt * doc: component design pattern doc * chore: component design pattern continued * chore: amount improvements * chore: copilot review * chore: amount improvements * refactor: mint and burn token screens use AmountInput * chore: use AmountInput on token creator screen * fix: burn error handling * feat: errors displayed in the AmountInput component * fix: vertical align of amount input * backport: amount component from * chore: fix imports * chore: refactor * chore: futher refactor * chore: further refactor based on feedback * doc: simplified component design pattern description * chore: peer review * doc: update docs * chore: amount input * chore: fixes after merge * chore: self-review * feat: amout set decimal places + rename label => with_label * refactor: amount input init on token screen * chore: fix token creator layout * chore: format base amount with leading zeros in confirmation * chore: base supply 0 by default * feat: add network field to identity structures (#423) * feat: add network field to identity structures * fix * feat: add display for private key in both WIF and Hex formats (#424) * feat: add display for private key in both WIF and Hex formats * fix: display private keys as normal text and depend on color theme --------- Co-authored-by: pauldelucia <pauldelucia2@gmail.com> * feat: allow setting zmq uri in .env (#425) * feat: allow setting ZMQ URI * chore: rename zmq_endpoint to core_zmq_endpoint * fix: failing test in token screen needed update * fix: update CI to use rust version 1.88 to match rust-toolchain * feat: better display in key selector (#429) * refactor: unified confirmation dialog (#413) * refactor: unified alert window * chore: update CLAUDE to create reusable components whenever appropriate * feat: correct confirm dialog on set token price screen * chore: remove callbacks which are overkill * chore: cargo fmt * chore: doctest fix * chore: impl Component for ConfirmationDialog * chore: use WidgetText * feat: Add Escape key handling for confirmation dialog * chore: button inactive when in progress * chore: fixes after merge * chore: some theme improvements * fmt and visual appeal --------- Co-authored-by: pauldelucia <pauldelucia2@gmail.com> * feat: nicer contract chooser panel (#426) * feat: nicer contract chooser panel * fmt * clippy * fix: token purchasability was not refreshing unless app restart (#432) * fix: token action buttons alignment * feat: nicer expanding tabs in token creator (#431) * feat: nicer expanding tabs in token creator * fix * feat: implement new ConfirmationDialog component throughout app (#430) * feat: implement new ConfirmationDialog component throughout app * fix: remove backup files * fix: confirmation dialog on withdrawal screen always showing "loading" * feat: Dash Masternode List and Quorum Viewer (#428) * a lot of work on DML viewer * more work * more work * more work * more work * more work * more work * more work * more work * ui improvements * ui improvements * optimizations * fast start * more work * more work * more work * fmt * much more work * fixes * updates * fix * fmt * revert * update for dashcore 40 * params for testnet * added testnet diff * fixes * clippy * more clippy * fixes * clean UI * use backend tasks * backend messages * coderabbit suggestions to add timeouts and prevent infinite loops * transient and fatal errors * update dash core configs for testnet * fmt * fix timeout * fix h-3 error * clear state when switching networks --------- Co-authored-by: pauldelucia <pauldelucia2@gmail.com> * chore: bump version to 1.0.0-dev (#439) The 1.0-dev branch builds were still reporting as 0.9.0 * feat: add left panel button labels and create contract subscreen chooser panel (#441) * feat: add left panel button labels and create contract subscreen chooser panel * fmt * feat: clarify identity index description for identity creation * fix: screen button labels display hard to see in dark mode * feat: left panel scroll (#443) * feat: left panel scroll * clippy * feat: add existing identity by wallet + identity index (#444) * feat: add existing identity by wallet + identity index * fmt * remove logging * update derivation index label * add robustness * fix: screen button labels display hard to see in dark mode * feat: left panel scroll (#443) * feat: left panel scroll * clippy * feat: load all identities up to an index * clippy * fix * feat: remove wallet (#445) * feat: remove wallet * clippy * Clarify wallet removal warning message Updated warning message for wallet removal to clarify that keys will no longer work unless the wallet is re-imported. * fix: identity creation and top-up via QR code handling (#447) * fix: identity creation handling * cleanup * cleanup * fix identity topup too * remove note * fix: keyword search required new platform version plus error handling and UI updates (#449) * fix: keyword search not displaying errors * update platform version and keyword search cleanup * fix * fix: handle decimals and fix schedules on price and purchase screens (#412) * fix: inactive button on set price group action * chore: apply review feedback * refactor: use token amount input * chore: update AmountInput * chore: tiered pricing * chore: direct purchase * chore: remove total agreed price * chore: max amount input defaults to max_credits * fmt * fix * clippy --------- Co-authored-by: pauldelucia <pauldelucia2@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> * fix: showing used asset locks as unused (#448) * chore: remove unused task sender * chore: update to Platform V10 * feat: GroveSTARK ZK proofs (#450) * works * works * fix * ok * ok * ok * ok * ok * fix verification message showing in generation screen * remove advanced settings. set default 16 grinding bits and 128 bit security * ok * lock * ok * clippy * fmt * clippy and fmt * pin grovestark dep * fix * ok * clippy * rename file * remove ProofData * cleanup * fix * rename GroveStark to GroveSTARK * rename zk_proofs_screen to grovestark_screen * rename ZKProofs tool subscreen to GroveSTARK * move grovestark prover to model * rename ContractsDashpayComingSoon to ContractsDashpay * rename ContractsDashpay to Dashpay * rename dashpay stuff * fixes * ok * update grovestark rev * update * chore: update grovestark rev * chore: bump version * update platform rev * clippy * fix * fix * fix release * fix release * fix release --------- Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: QuantumExplorer <quantum@dash.org> Co-authored-by: thephez <thephez@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
* feat: wallet unlock on wallet screen (#415) * refactor: Amount type and AmountInput component (#417) * feat: amount input, first building version * test(amount): fixed tests * chore: I think final * chore: my_tokens display correct amount * chore: transfer tokens update * chore: hide unit on rewards estimate column * chore: two new helper methods * chore: I think finals * cargo fmt * feat: component trait * impl Component for AmountInput * chore: updated component trait * chore: update for egui enabled state mgmt * doc: component design pattern doc * chore: component design pattern continued * chore: amount improvements * chore: copilot review * chore: amount improvements * backport: amount component from * chore: fix imports * chore: refactor * chore: futher refactor * chore: further refactor based on feedback * doc: simplified component design pattern description * chore: peer review * doc: update docs * chore: amount input * test: run tests using github actions and fix failing tests (#422) * fix: failing tests * gha: run tests * fix: tests fail due to lack of .env file * fix: incorrect decimals handling on token create, mint and burn screens (#419) * feat: amount input, first building version * test(amount): fixed tests * chore: I think final * chore: my_tokens display correct amount * chore: transfer tokens update * chore: hide unit on rewards estimate column * chore: two new helper methods * chore: I think finals * cargo fmt * feat: component trait * impl Component for AmountInput * chore: updated component trait * chore: update for egui enabled state mgmt * doc: component design pattern doc * chore: component design pattern continued * chore: amount improvements * chore: copilot review * chore: amount improvements * refactor: mint and burn token screens use AmountInput * chore: use AmountInput on token creator screen * fix: burn error handling * feat: errors displayed in the AmountInput component * fix: vertical align of amount input * backport: amount component from * chore: fix imports * chore: refactor * chore: futher refactor * chore: further refactor based on feedback * doc: simplified component design pattern description * chore: peer review * doc: update docs * chore: amount input * chore: fixes after merge * chore: self-review * feat: amout set decimal places + rename label => with_label * refactor: amount input init on token screen * chore: fix token creator layout * chore: format base amount with leading zeros in confirmation * chore: base supply 0 by default * feat: add network field to identity structures (#423) * feat: add network field to identity structures * fix * feat: add display for private key in both WIF and Hex formats (#424) * feat: add display for private key in both WIF and Hex formats * fix: display private keys as normal text and depend on color theme --------- Co-authored-by: pauldelucia <pauldelucia2@gmail.com> * feat: allow setting zmq uri in .env (#425) * feat: allow setting ZMQ URI * chore: rename zmq_endpoint to core_zmq_endpoint * fix: failing test in token screen needed update * fix: update CI to use rust version 1.88 to match rust-toolchain * feat: better display in key selector (#429) * refactor: unified confirmation dialog (#413) * refactor: unified alert window * chore: update CLAUDE to create reusable components whenever appropriate * feat: correct confirm dialog on set token price screen * chore: remove callbacks which are overkill * chore: cargo fmt * chore: doctest fix * chore: impl Component for ConfirmationDialog * chore: use WidgetText * feat: Add Escape key handling for confirmation dialog * chore: button inactive when in progress * chore: fixes after merge * chore: some theme improvements * fmt and visual appeal --------- Co-authored-by: pauldelucia <pauldelucia2@gmail.com> * feat: nicer contract chooser panel (#426) * feat: nicer contract chooser panel * fmt * clippy * fix: token purchasability was not refreshing unless app restart (#432) * fix: token action buttons alignment * feat: nicer expanding tabs in token creator (#431) * feat: nicer expanding tabs in token creator * fix * feat: implement new ConfirmationDialog component throughout app (#430) * feat: implement new ConfirmationDialog component throughout app * fix: remove backup files * fix: confirmation dialog on withdrawal screen always showing "loading" * feat: Dash Masternode List and Quorum Viewer (#428) * a lot of work on DML viewer * more work * more work * more work * more work * more work * more work * more work * more work * ui improvements * ui improvements * optimizations * fast start * more work * more work * more work * fmt * much more work * fixes * updates * fix * fmt * revert * update for dashcore 40 * params for testnet * added testnet diff * fixes * clippy * more clippy * fixes * clean UI * use backend tasks * backend messages * coderabbit suggestions to add timeouts and prevent infinite loops * transient and fatal errors * update dash core configs for testnet * fmt * fix timeout * fix h-3 error * clear state when switching networks --------- Co-authored-by: pauldelucia <pauldelucia2@gmail.com> * chore: bump version to 1.0.0-dev (#439) The 1.0-dev branch builds were still reporting as 0.9.0 * feat: add left panel button labels and create contract subscreen chooser panel (#441) * feat: add left panel button labels and create contract subscreen chooser panel * fmt * feat: clarify identity index description for identity creation * fix: screen button labels display hard to see in dark mode * feat: left panel scroll (#443) * feat: left panel scroll * clippy * feat: add existing identity by wallet + identity index (#444) * feat: add existing identity by wallet + identity index * fmt * remove logging * update derivation index label * add robustness * fix: screen button labels display hard to see in dark mode * feat: left panel scroll (#443) * feat: left panel scroll * clippy * feat: load all identities up to an index * clippy * fix * feat: remove wallet (#445) * feat: remove wallet * clippy * Clarify wallet removal warning message Updated warning message for wallet removal to clarify that keys will no longer work unless the wallet is re-imported. * fix: identity creation and top-up via QR code handling (#447) * fix: identity creation handling * cleanup * cleanup * fix identity topup too * remove note * fix: keyword search required new platform version plus error handling and UI updates (#449) * fix: keyword search not displaying errors * update platform version and keyword search cleanup * fix * fix: handle decimals and fix schedules on price and purchase screens (#412) * fix: inactive button on set price group action * chore: apply review feedback * refactor: use token amount input * chore: update AmountInput * chore: tiered pricing * chore: direct purchase * chore: remove total agreed price * chore: max amount input defaults to max_credits * fmt * fix * clippy --------- Co-authored-by: pauldelucia <pauldelucia2@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> * fix: showing used asset locks as unused (#448) * chore: remove unused task sender * chore: update to Platform V10 * feat: GroveSTARK ZK proofs (#450) * works * works * fix * ok * ok * ok * ok * ok * fix verification message showing in generation screen * remove advanced settings. set default 16 grinding bits and 128 bit security * ok * lock * ok * clippy * fmt * clippy and fmt * pin grovestark dep * fix * ok * clippy * rename file * remove ProofData * cleanup * fix * rename GroveStark to GroveSTARK * rename zk_proofs_screen to grovestark_screen * rename ZKProofs tool subscreen to GroveSTARK * move grovestark prover to model * rename ContractsDashpayComingSoon to ContractsDashpay * rename ContractsDashpay to Dashpay * rename dashpay stuff * fixes * ok * update grovestark rev * update * chore: update grovestark rev * chore: update platform to v2.1.2 * feat: derive keys from loaded wallets when loading identity by ID (#446) * feat: derive keys from loaded wallets when loading identity * clippy * chore: update platform version * ok * cleanup ui * cleanup ui * set max index search to 30 * set max const * k * fix: wallet screen not updating wallets after network change (#451) * fix: wallet screen not updating wallets after network change * ui improvement * clippy * fix: some document actions were showing error when it was success (#452) * fix: some document actions were showing error when it was success * add space at bottom * feat: wallet unlock button (#459) * fix: scrollable unused asset locks on identity creation (#460) * fix: no error display when trying to import a wallet twice on different networks (#466) * fix: no error display when trying to import a wallet twice on different networks * feat: add waiting for valid seed phrase message * fix * fix: logging should interpret RUST_LOG env variable (#467) * feat: signed dmg for mac (#437) * feat: signed mac binaries and dmg * fix * fix * extra check * app bundle * fix * fix icon * feat: simplify icon padding to 3% for correct sizing * ok * ok * fmt * fix: split dmgs into arm64 and x86 instead of universal * cleanup * fmt * fix naming * ok * fix * disk space fix * fix * fix * fix attempt * fix: enhance disk space cleanup for macOS DMG creation - Add more aggressive cleanup of Xcode caches and derived data - Remove additional Cargo build artifacts (.rlib, .d files) - Clean system-level caches to free maximum space - Add cleanup step for both ARM64 and x86_64 macOS builds - Remove temporary icon files after app bundle creation This should resolve the "No space left on device" error during DMG creation on GitHub Actions runners. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * macos-latest * latest for arm too * revert * re-revert * clear cache * fix * cleanup * try large * omg * apply suggestion * cleanup * fix * fix * fix --------- Co-authored-by: Claude <noreply@anthropic.com> * feat: HD wallet system, DashPay integration, SPV support, and more (#464) * feat: dashpay * ok * ok * remove doc * ok * ok * database * ok * fix: use proper BackendTaskSuccessResults rather than Message * fmt and clippy * remove dashpay dip file * logo and cleanup * fix top panel spacing * ui stuff * fmt * dip 14 * image fetching * some fixes * cleaning up * todos * feat: SPV phase 1 (#440) * feat: spv in det * ui * progress bars * working progress updates * fmt * fast sync * add back progress monitoring * back to git dep * newer dashcore version * deduplication * spv context provider * fixes * small fix * clippy fixes * fixes --------- Co-authored-by: Quantum Explorer <quantum@dash.org> * feat: spv progress bars and sync from genesis when wallets are loaded (#454) * feat: spv progress bars * feat: start from 0 if syncing with wallets * clippy * fmt * update * fixes * fix: add sdk features * feat: add accounts and transactions to wallet screen * clippy * fmt * fix: dashpay database table initialization was hanging on new db (#463) * fix: display stuff * add accounts and much progress * feat: transaction history in wallet * clippy * ok * feat: hd wallet * send tx via wallet and wallet lock/unlock * update to PeerNetworkManager * ok * ok * ok * fmt * clippy * clippy * feat: clear SPV data button * fix: switch from dash core rpc to spv mode * feat: switch to DashSpvClientInterface * clean spv button fix * feat: send from wallet screen * feat: platform addresses * feat: platform address transitions * feat: platform address transitions * feat: move dashpay screen to top level * platform addresses sdk * remove async context provider fn * lock * update for new sdk with addresses and handle sdk result data * chore: update grovestark dependency * chore: update dash-sdk rev * fmt * remove elliptic curves patch * clippy * feat: use BackendTaskSuccessResult variants instead of Message(String) * fmt * clippy * update DIP18 implementation, fixes and some features around wallets and PAs * fix * wallet unlock on wallet screen * info popup component * small fixes * wallet unlock component * fix startup panic * welcome screen and dashpay stuff * cargo fix * cargo fmt * chore: update deps to use most recent dash-sdk * simplify welcome screen and move spv storage clear to advanced settings * default connect to peers via SPV DNS seeds * fix: exit app without waiting * fix error message and reverse quorum hash on lookup * fmt * settings to turn off spv auto sync * clippy * work on getting started flow * AddressProvider stuff * address sync stuff * many fixes all in one * fix * many fixes * fixes * amount input stuff * alignment in identity create screen for adding keys * more fixes * many improvements * simple token creator, word count selection for wallet seed phrases, more * fix: platform address info storage * feat: generate platform addresses and address sync post-checkpoint * many things * chore: update to recent changes in platform * docs: added few lines about .env file * fix: banned addresses and failure during address sync * fix: updates for new platform and fee estimation * fix: only take PA credits after checkpoint * feat: fee estimation and display * feat: fee estimation follow-up * more on fee displays * fix: proof logs in data contract create * fix: white on white text for fee estimation display * fix: always start as closed for advanced settings dropdown in settings screen * fix: hard to see data contracts in the register contract screen * fix: document create screen scroll * fix: fee estimations accuracy * fmt * clippy auto fixes * clippy manual fixes and pin dash-sdk dep * fix failing tests * fmt * fix: update rust toolchain to 1.92 * refactor: hide SPV behind dev mode * feat: warning about SPV being experimental * cleanup based on claude review * fmt * cleanup based on another claude review * fix: kittest failing * fix: remove fee result display in success screens and clean up dashpay avatar display * dashpay fixes and platform address fixes * refactor: move some AppContext functions to backend_task module * clippy * clippy * fix: refresh mode alignment in wallet screen and fmt * fix: failing test due to test_db issue * fix: dashpay avatar loading slow * fix: add rocksdb deps to ci workflow * fix: free up disk space in ci workflow * fix: display warning when partial wallet refresh success occurs * fix: propogate error for terminal balance sync * feat: more aggressive disk cleanup in ci workflow --------- Co-authored-by: Quantum Explorer <quantum@dash.org> Co-authored-by: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Co-authored-by: Ivan Shumkov <ivanshumkov@gmail.com> * feat: comprehensive test coverage implementation (#481) * feat: comprehensive test suite * fmt * fix: cannot create identity from address due to wrong identity id (#470) * feat: dashpay * ok * ok * remove doc * ok * ok * database * ok * fix: use proper BackendTaskSuccessResults rather than Message * fmt and clippy * remove dashpay dip file * logo and cleanup * fix top panel spacing * ui stuff * fmt * dip 14 * image fetching * some fixes * cleaning up * todos * feat: SPV phase 1 (#440) * feat: spv in det * ui * progress bars * working progress updates * fmt * fast sync * add back progress monitoring * back to git dep * newer dashcore version * deduplication * spv context provider * fixes * small fix * clippy fixes * fixes --------- Co-authored-by: Quantum Explorer <quantum@dash.org> * feat: spv progress bars and sync from genesis when wallets are loaded (#454) * feat: spv progress bars * feat: start from 0 if syncing with wallets * clippy * fmt * update * fixes * fix: add sdk features * feat: add accounts and transactions to wallet screen * clippy * fmt * fix: dashpay database table initialization was hanging on new db (#463) * fix: display stuff * add accounts and much progress * feat: transaction history in wallet * clippy * ok * feat: hd wallet * send tx via wallet and wallet lock/unlock * update to PeerNetworkManager * ok * ok * ok * fmt * clippy * clippy * feat: clear SPV data button * fix: switch from dash core rpc to spv mode * feat: switch to DashSpvClientInterface * clean spv button fix * feat: send from wallet screen * feat: platform addresses * feat: platform address transitions * feat: platform address transitions * feat: move dashpay screen to top level * platform addresses sdk * remove async context provider fn * lock * update for new sdk with addresses and handle sdk result data * chore: update grovestark dependency * chore: update dash-sdk rev * fmt * remove elliptic curves patch * clippy * feat: use BackendTaskSuccessResult variants instead of Message(String) * fmt * clippy * update DIP18 implementation, fixes and some features around wallets and PAs * fix * wallet unlock on wallet screen * info popup component * small fixes * wallet unlock component * fix startup panic * welcome screen and dashpay stuff * cargo fix * cargo fmt * chore: update deps to use most recent dash-sdk * simplify welcome screen and move spv storage clear to advanced settings * default connect to peers via SPV DNS seeds * fix: exit app without waiting * fix error message and reverse quorum hash on lookup * fmt * settings to turn off spv auto sync * clippy * work on getting started flow * AddressProvider stuff * address sync stuff * many fixes all in one * fix * many fixes * fixes * amount input stuff * alignment in identity create screen for adding keys * more fixes * many improvements * simple token creator, word count selection for wallet seed phrases, more * fix: platform address info storage * feat: generate platform addresses and address sync post-checkpoint * many things * fix: cannot create identity from address * chore: update to recent changes in platform * docs: added few lines about .env file * fix: banned addresses and failure during address sync * fix: updates for new platform and fee estimation * fix: only take PA credits after checkpoint * feat: fee estimation and display * feat: fee estimation follow-up * chore: fix build * chore: correct platform revision * refactor: don't query for nonce when creating identity * more on fee displays * fix: proof logs in data contract create * fix: white on white text for fee estimation display * fix: always start as closed for advanced settings dropdown in settings screen * fix: hard to see data contracts in the register contract screen * fix: document create screen scroll * fix: fee estimations accuracy * fmt * clippy auto fixes * clippy manual fixes and pin dash-sdk dep * fix failing tests * fmt * fix: update rust toolchain to 1.92 * refactor: hide SPV behind dev mode * feat: warning about SPV being experimental * fix: platform nonces not updated in sync * chore: cargo fmt * deps: update platform repo * chore: clippy and rabbit * chore: rabbit review * chore: enforce address networ with require_network() * cleanup based on claude review * fmt * cleanup based on another claude review * fix: kittest failing * fix: remove fee result display in success screens and clean up dashpay avatar display * dashpay fixes and platform address fixes * deps: update platform repo * chore: fixes after merge * refactor: move some AppContext functions to backend_task module * clippy * clippy * fix: refresh mode alignment in wallet screen and fmt * chore: fmt * fmt --------- Co-authored-by: pauldelucia <pauldelucia2@gmail.com> Co-authored-by: Paul DeLucia <69597248+pauldelucia@users.noreply.github.com> Co-authored-by: Quantum Explorer <quantum@dash.org> Co-authored-by: Ivan Shumkov <ivanshumkov@gmail.com> * docs: add CLAUDE.md for Claude Code guidance (#484) Adds documentation to help Claude Code (claude.ai/code) work effectively with this codebase, including build commands, testing instructions, architecture overview, and UI component patterns. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * build: update dash-sdk to use rust-dashcore v0.42-dev (#483) * build: update dash-sdk to use rust-dashcore v0.41.0 Updates dash-sdk dependency to rev 7b2669c0b250504a4cded9e2b9e78551583e6744 which includes rust-dashcore v0.41.0. Breaking changes addressed: - WalletBalance: confirmed field renamed to spendable(), fields now methods - WalletManager::new() now requires Network argument - import_wallet_from_extended_priv_key() no longer takes network argument - current_height() no longer takes network argument - RequestSettings: removed max_decoding_message_size field - sync_to_tip() removed - initial sync now handled by monitor_network() Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * style: apply cargo fmt Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * clippy --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: pauldelucia <pauldelucia2@gmail.com> * feat: hint text next to withdrawal destination input in dev mode with advanced options and owner key * feat: implement asset lock creation and detail screens (#418) * feat: implement asset lock creation and detail screens * clippy fix * some fixes * fix: ui cleanup and backend fixes * fix: clippy * feat: tests * fix: remove identity index selector for top ups * fmt * refactor: use `AmountInput` component * fixes * fix: clippy --------- Co-authored-by: pauldelucia <pauldelucia2@gmail.com> * fix: dev mode wouldnt toggle in left panel when unchecked in settings if config load failed (#488) * fix: force Core RPC mode on app start if not in dev mode (#489) * fix: display WIF format for manually added private keys (#496) * fix: display WIF format for manually added private keys Externally loaded identities with manually added private keys now show both WIF and hex formats, matching the display for wallet-derived keys. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * clippy * fmt --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: pauldelucia <pauldelucia2@gmail.com> * fix: security level validation for add key screen (#494) * fix: auto-set security level based on key purpose in add key screen When selecting a key purpose, automatically set the appropriate security level and restrict available options: ENCRYPTION/DECRYPTION only allow MEDIUM, TRANSFER only allows CRITICAL, and AUTHENTICATION allows CRITICAL/HIGH/MEDIUM. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: disable security level dropdown when only one option is valid Visually indicate to the user that the security level is fixed by the protocol for certain key purposes (ENCRYPTION, DECRYPTION, TRANSFER). Adds a hover tooltip explaining why the dropdown is disabled. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: remove redundant `contract_bounds_enabled` check for `has_multiple_security_levels` bool * fmt --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: pauldelucia <pauldelucia2@gmail.com> * fix: identity registration default key was using wrong `ContractBounds` (#487) * fix: identity registration default key was using wrong ContractBounds * feat: add tests * fmt * doc: update key descriptions * feat: add coderabbit configuration file * fix: document actions were auto selecting master keys but shouldnt (#493) * fix: top up with QR was validating against wallet max balance (#492) * fix: view platform address popup showing wrong address format (#500) * fix: view platform address popup showing wrong address format * fix: use helper * feat: update sdk v3.0.1 hotfix.1 (#503) * chore: update dash-sdk to v3.0.1-hotfix.1 Updates dash-sdk to v3.0.1-hotfix.1 to match testnet. Breaking API changes addressed: - WalletBalance.unconfirmed and .total are now fields instead of methods - RequestSettings now requires max_decoding_message_size field Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fmt --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix: ensure dev mode is off and spv sync off for new users (#504) * fix: ensure dev mode is off and spv sync off for new users * fix tests * fix * fix: update platform address prefix from dashevo to evo (#505) * fix: update platform address prefix from dashevo to evo Update address detection and UI hints to use the new shorter platform address prefixes (evo1/tevo1) instead of the old format (dashevo1/tdashevo1) to match SDK v3.0.1 changes. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: validate platform address network matches app network Add network validation when parsing Bech32m Platform addresses to ensure the address network prefix matches the app's configured network, showing a descriptive error on mismatch. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fmt --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix: platform address balance doubling after transfer and refresh (#502) * fix: platform address balance doubling after transfer and refresh * fix * feat: add fee multiplier caching and use it across all UI screens (#506) * feat: add fee multiplier caching and use it across all UI screens - Add fee_multiplier_permille support to PlatformFeeEstimator - Add fee multiplier caching in AppContext with getter/setter - Add fee_estimator() helper method on AppContext - Cache the fee multiplier when epoch info is fetched - Display note when fee multiplier cache is updated - Update all UI screens to use app_context.fee_estimator() Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fmt * fix: apply fee multiplier to all estimation functions Update all estimate_* functions to apply the fee multiplier to the combined total (storage + processing/registration) rather than to individual components, ensuring consistent fee calculation across all state transition types per the Dash Platform spec. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: reuse fee_estimator instance in token screens Avoid duplicate construction and keep consistent multiplier snapshot within the frame by reusing the existing fee_estimator variable. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: use DEFAULT_FEE_MULTIPLIER_PERMILLE constant in AppContext Keep the AppContext default in sync with the estimator's canonical value instead of hardcoding 1000. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix: take from multiple platform addresses in simple send flow (#501) * fix: take from multiple platform addresses in simple send flow * address selection algorithm * fix * fix: fee payer index lookup * cleanup * fix: use PlatformFeeEstimator for address transfer fees - Replace custom fee calculation with PlatformFeeEstimator - Simplify allocation logic by calculating fee upfront - Use 20% safety buffer on fee estimates - Remove complex iterative allocation loop Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fmt * Add fee deficit check in platform address allocation The fee payer must have enough remaining balance after their contribution to cover the transaction fee. This change calculates the fee deficit (if fee payer's remaining balance < estimated fee) and adds it to the shortfall, preventing impossible sends from being attempted. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Use actual input count for fee estimation in error messages Changed estimate_platform_fee calls to use addresses_available (the actual number of available inputs) instead of MAX_PLATFORM_INPUTS. This provides more accurate fee estimates and max sendable amounts in the error messages when transactions exceed available balance. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Filter destination address from preview allocation The preview allocation now parses the destination platform address and passes it to allocate_platform_addresses, ensuring the destination is never shown as an input source. This matches the behavior of the actual send logic. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fmt * Filter destination from max calculation and improve warning message The max amount calculation now excludes the destination address, matching the allocation logic. This prevents showing an inflated max when the destination is one of your own addresses. Also improved the warning message to distinguish between exceeding the address limit vs insufficient balance (including fees). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fmt * feat: use cached fee multiplier in send_screen Update estimate_platform_fee and allocate_platform_addresses to accept a PlatformFeeEstimator parameter, allowing the send screen to use the cached network fee multiplier from app_context.fee_estimator(). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address review comments in send_screen - Add early return for empty sorted_addresses in allocate_platform_addresses - Use safe string slicing in render_platform_source_breakdown to avoid panic - Remove duplicate doc comment Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix: prevent platform address balance doubling after internal updates (#507) * fix: prevent platform address balance doubling after internal updates Adds last_full_sync_balance column to track the balance checkpoint for terminal sync pre-population, separate from the current balance. Key changes: - Add DB migration (v26) for last_full_sync_balance column - Sync operations update last_full_sync_balance for next sync baseline - Internal updates (after transfers) preserve last_full_sync_balance - Terminal sync pre-populates with last_full_sync_balance, applies AddToCredits correctly without double-counting This fixes the scenario where: 1. Transfer completes, balance updated internally 2. App restarts, refresh triggers terminal sync 3. Same AddToCredits was being re-applied because the pre-population baseline wasn't distinguishing between sync and internal updates Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: fix docblocks for is_sync_operation and last_full_sync_balance - Remove duplicate/obsolete is_full_sync wording from set_platform_address_info - Update last_full_sync_balance field doc to accurately describe when it's updated (during syncs) vs preserved (during internal updates) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: preserve last_full_sync_balance when removing duplicate address entries Search for last_full_sync_balance from any canonical-equivalent entry BEFORE removing duplicates, so the value isn't lost when the existing entry has a different Address representation. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix: fetch fresh nonces from platform for identity creation (#509) When creating an identity with Platform Address funding, the cached nonce could be stale (terminal-only sync only updates balance, not nonce). This caused "Invalid address nonce" errors. Now fetches fresh nonces from platform using AddressInfo::fetch_many() before identity creation. Note: The SDK's put_with_address_funding requires caller-provided nonces, unlike transfer_address_funds which handles nonces internally. This inconsistency should be addressed in the SDK. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix: don't auto-generate platform address when opening receive dialog (#508) Use platform_addresses() which checks watched_addresses for derived Platform addresses, instead of only checking platform_address_info which only contains synced addresses with balances. A new address is now only generated if there are truly no Platform addresses derived for the wallet, not just because they haven't been synced yet. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix: show N/A for UTXOs and Total Received columns on Platform addresses (#510) Platform addresses don't have UTXOs (they have credits on Platform layer) and we don't track historical received amounts for them. Showing 0 was misleading - N/A is more accurate. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix: reserve fees when using max button for platform address identity funding (#511) * fix: reserve fees when using max button for platform address identity funding When clicking the max button to fund identity creation or top-up from a platform address, the full balance was used without reserving room for transaction fees, causing "Insufficient combined address balances" errors. Changes: - Subtract estimated fee from max amount in identity creation screen - Subtract estimated fee from max amount in identity top-up screen - Fix fee estimation to use identity_create_asset_lock_cost (200M credits) instead of address_funding_asset_lock_cost (50M credits) - Add storage-based fees to identity creation/top-up fee estimates - Add new estimate_identity_topup_from_addresses() for platform address top-ups - Add 20% safety buffer to account for fee variability - Show hint explaining fee reservation when max is used Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: fix docstrings to correctly state 20% safety buffer The docstrings incorrectly stated 10% safety buffer while the code applies 20% via total / 5. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * Release SPV storage lock on shutdown (#517) * Fix dark mode text colors (#515) * Fix dark mode text and borders * style: apply cargo fmt formatting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix: invalid min amount when transferring funds (#523) * fix: invalid min amount when transferring funds * chore: rabbit's feedback * chore: update bincode to 2.0.1, dash-sdk to v3.1-dev, and grovestark (#526) * chore: update bincode to 2.0.1, dash-sdk to v3.1-dev, and grovestark - Update bincode from 2.0.0-rc.3 to 2.0.1 - Update dash-sdk to latest v3.1-dev (98a0ebec) - Update grovestark to a70bdb1a - Fix Decode/BorrowDecode implementations for bincode 2.0.1 API changes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: migrate to using dashpay/grovestark --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: pasta <pasta@dashboost.org> * feat: use DAPI instead of Core RPC for historical asset lock transaction info (#528) Replace core_client.get_raw_transaction_info() calls with a new get_transaction_info_via_dapi() function that queries transaction status via DAPI gRPC. This removes the dependency on a local Core RPC node for checking whether asset lock transactions have been chainlocked, which is needed for identity registration, top-up, and platform address funding from asset locks. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix: not enough balance to pay a fee in platform to core transfers (#513) * fix: fee estimation for AddressCreditWithdrawalTransition * chore: max button * refactor: remove redundant code * chore: better hint in platform-to-core * Refactor token creator helpers (#518) * refactor(tokens): simplify token creator helpers * style: cargo fmt * Simplify wallets UI helpers and send flow (#519) * Simplify wallets UI helpers and send flow * Fix wallets screen helper placement * Fix refresh_on_arrival borrow * Stabilize token UI tests config * Simplify wallet send address type helper * fix: handle RegisteredTokenContract result to clear token creation spinner (#529) The backend task returned RegisteredTokenContract on success but the tokens screen had no handler for it, causing the spinner to spin forever. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix: build fails for windows target (#527) * fix: build fails for windows target * build: only create a release when tag is set * chore: remove redundant settings from release.yml * doc: windows requirements * fix: windows icon * build: change grovestark revision * chore: fmt * fix: don't open console window on windows * build: grovestark recent commit * fix: critical wallet bugs (GH#522, GH#476, GH#478, GH#85) (#534) * fix: auto-refresh wallet UTXOs on app startup (GH#522) On startup, bootstrap_loaded_wallets now spawns background tasks to refresh UTXOs from Core RPC for all HD and single-key wallets. This ensures balances are current without requiring the user to manually click Refresh. Only applies in RPC mode; SPV handles UTXOs via reconciliation. Task: 1.1a * fix: respect fee_deduct_from_output flag in platform address funding (GH#476) When the user selects "deduct from input", use an explicit output amount for the destination and a separate change address for the fee remainder, so the destination receives the exact requested amount. Task: 1.1b * fix: reserve estimated fees in wallet balance top-up max button (GH#478) Task: 1.1c * fix: prevent funding address reuse across identities (GH#85) Task: 1.1d * fix: add 5-minute timeout to asset lock proof wait loop (wallet-008) Task: 1.1e * fix: use wallet-controlled change address and epoch-aware fee estimator Use a fresh wallet receive address for platform funding change output instead of an ephemeral key-derived address, so surplus credits remain spendable. Also switch to epoch-aware fee estimator for accurate fee estimation when the network fee multiplier is above 1x. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address critical review issues in wallet funding - Use try_lock() in tokio::select! timeout arm to avoid blocking the async runtime when another thread holds the mutex - Use change_address() (BIP44 internal path) instead of receive_address() for deriving change addresses, ensuring proper path separation - Replace .unwrap_or(0) with .ok_or() on BTreeMap index lookup to surface errors instead of silently targeting the wrong output Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: auto-refresh wallet UTXOs on asset lock proof timeout (RPC mode) When the 5-minute timeout fires, the asset lock tx has already been broadcast and UTXOs removed locally. Trigger a background wallet refresh in RPC mode so spent inputs are reconciled against chain state. SPV mode handles its own reconciliation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style: fix rustfmt formatting in fee estimator chain Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: replace saturating_mul with checked_mul for duffs-to-credits conversion Overflow now returns an explicit error with diagnostic info instead of silently clamping to u64::MAX. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix(tokens): restore token reorder assignment and distribution field checks (#535) * Extract dialog rendering into wallets_screen/dialogs.rs module (#539) Moved 4 dialog rendering functions and 10+ helper methods (~1151 lines) from wallets_screen/mod.rs into a new dialogs.rs module. Includes send, receive, fund platform, and private key dialogs plus their state structs. mod.rs reduced from 3824 to 2673 lines. Task: 3.2a * build: update all dependencies (#531) * fix: build fails for windows target * build: only create a release when tag is set * chore: remove redundant settings from release.yml * doc: windows requirements * fix: windows icon * build: change grovestark revision * chore: fmt * fix: don't open console window on windows * build: grovestark recent commit * build: update dependencies * chore: clippy * chore: fmt * build: update platform to most recent v3.1-dev * feat: add key exchange protocol and state transition signing Add YAPPR key exchange flow for DashPay, QR scanner improvements, state transition signing screen, and refactor UI helpers. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: migrate SPV event handling to broadcast channels Replace orphaned SpvEvent handler with three new broadcast-based handlers (SyncEvent, WalletEvent, NetworkEvent) that subscribe to the actual event producers in dash-spv. This fixes wallet reconciliation never being triggered by SPV events. - Bump dash-sdk to fb055ec008 (picks up rust-dashcore 4d2a7018 with WalletEvent support) - Add spawn_sync_event_handler: triggers reconcile on BlockProcessed, ChainLockReceived, InstantLockReceived, SyncComplete - Add spawn_wallet_event_handler: triggers reconcile on all wallet events (TransactionReceived, BalanceUpdated) - Add spawn_network_event_handler: updates connected_peers count on PeersUpdated - Add connected_peers field to SpvManager and SpvStatusSnapshot - Fix reconcile channel race: register channel before starting SPV thread so handlers always capture a valid sender - Improve reconcile: track in-memory UTXOs, log summaries, guard against wiping transaction history Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: refresh receive dialog balances from wallet on each frame The receive dialog cached address balances at open time and never updated them, so SPV balance changes were not reflected until the dialog was closed and reopened. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: remove YAPPR key exchange and state transition signing Move these features to the feat/yappr-key-exchange branch. This branch now focuses on SPV broadcast channel migration, dependency bumps, and reconciliation fixes only. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: replace Core RPC with DAPI for asset lock operations in SPV mode Migrate transaction info queries, broadcasting, and finality detection away from direct Core RPC calls so that identity registration and top-up work in SPV-only mode. Key changes: - Add `get_transaction_info_via_dapi()` using DAPI GetTransaction - Add `broadcast_raw_transaction()` that routes via RPC or SPV - Add SPV finality listener forwarding instant/chain lock events - Make asset lock creation methods async for SPV broadcasting - Use longer proof timeouts (5min) in SPV mode vs 2min for RPC - Update address balances after asset lock UTXO consumption - Add BIP32 derivation path detection for SPV address mapping - Bump platform SDK rev to bcb41de347 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * style: apply cargo fmt formatting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: handle ignored Results and avoid panic on poisoned lock - Propagate update_address_balance errors via ? in create_asset_lock.rs - Replace .expect() with .map_err()? for core_client lock in broadcast_raw_transaction - Log try_send failures for finality events in SPV manager instead of silently dropping Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: clean up finality map on success and remove poisoned lock panic Remove stale entries from transactions_waiting_for_finality on the success path of asset lock proof timeout loops, preventing unbounded map growth. Applied to both top_up_identity.rs and register_identity.rs. Also replace .expect() on poisoned RwLock read of core_client with graceful error propagation via map_err. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: address PR #525 review feedback from @lklimek - Rename get_transaction_info_via_dapi to get_transaction_info - Extract wait_for_asset_lock_proof helper on AppContext (4 copies → 1) - Extract recalculate_affected_address_balances and recalculate_address_balance helpers on Wallet (7 copies → helper calls) - Fix unused height variable suppression in ChainLock handler - Document single-subscriber semantics on register_finality_channel and register_reconcile_channel - Fix pre-existing collapsible_if clippy warnings in determine_sync_stage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Refactor masternode list diff screen state (#520) * refactor: split masternode list diff screen state * fix: avoid borrows in diff screen renders * Initial plan * refactor: split context.rs into focused submodules (#543) Extract the monolithic 1795-line context.rs into a context/ module with 5 focused submodules, each grouping related AppContext methods: - mod.rs (543 lines): struct definition, constructor, config/SDK methods - wallet_lifecycle.rs (572 lines): SPV/wallet management and reconciliation - identity_db.rs (205 lines): identity and DPNS database operations - contract_token_db.rs (198 lines): contract and token database operations - settings_db.rs (84 lines): settings cache and persistence - transaction_processing.rs (231 lines): transaction finality handling Pure extraction with no logic changes. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * refactor: extract address table, asset locks, and single-key view from wallets_screen (#542) Continue the wallets_screen/mod.rs refactoring started in #539 (dialogs extraction). Extract three more focused submodules: - address_table.rs: SortColumn/SortOrder enums, AddressData struct, sorting logic, categorize_path, and the full address table renderer - asset_locks.rs: asset lock table rendering and fund dialog triggers - single_key_view.rs: single-key wallet detail view with UTXO display Reduces mod.rs from 2662 to 1947 lines (-27%). Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix(startup): harden cookie parsing, config save, and logger init (#537) * fix(startup): harden cookie parsing, config save, and logger init * style(logging): apply rustfmt in logger init * fix(startup): use sync_all, fix Windows rename, and remove credential leak - Use with_file_name instead of with_extension for temp file path clarity - Replace flush() with sync_all() for crash-safe atomic config writes - Handle Windows rename semantics by removing target before rename - Remove raw cookie value from error message to prevent credential leakage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style: apply rustfmt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(config): use NamedTempFile::persist() for atomic config save on Windows Replace manual remove-then-rename sequence with tempfile::NamedTempFile which uses MoveFileEx(MOVEFILE_REPLACE_EXISTING) on Windows for atomic file replacement. This fixes two issues: - Config loss if process crashes between remove_file and rename - Open file handle on tmp file preventing rename on Windows Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: propagate errors from wallet balance recalculation instead of silently dropping Replace `let _ = wallet.recalculate_*()` with `?` in 5 call sites so database errors during address-balance recalculation are surfaced instead of silently swallowed. This matches the existing pattern in create_asset_lock.rs which already propagates these errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: update dash-sdk to platform rev 060515987a Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: cargo fmt * fix: connection status not clear (#532) * fix: connection status not updated * chore: rabbit feedback * chore: typo + network changes * chore: apply feedback * chore: rabbit review * chore: rabbit feedback * chore: rabbitting * chore: fmt --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: error when SPV sync height unknown instead of defaulting to 0 Passing height=0 into transaction construction when SPV hasn't synced yet can lead to incorrect locktime/maturity behavior. Return an error instead so the caller knows to wait for sync progress. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Merge pull request #548 from dashpay/chore/improve-claude-md chore: improve CLAUDE.md with architecture documentation * docs: use v1.0-dev for diffs etc agents (#551) * fix: remove dead code with guaranteed mutex deadlock (#559) * Initial plan * Remove unused insert_remote_identity_if_not_exists function with deadlock bug Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * feat: add "Claim all" checkbox and complete merge with v1.0-dev - Added claim_all boolean field to ClaimTokens task - Updated handler to call claim_all_tokens or claim_token based on flag - Added claim_all checkbox to UI (enabled by default) - Added claimed_amount field to track tokens claimed - Updated display_task_result to save and display claimed amount - Updated success screen to show amount of tokens claimed - Wire checkbox state to ClaimTokens backend task Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --------- Co-authored-by: Paul DeLucia <69597248+pauldelucia@users.noreply.github.com> Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> Co-authored-by: QuantumExplorer <quantum@dash.org> Co-authored-by: pauldelucia <pauldelucia2@gmail.com> Co-authored-by: thephez <thephez@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Ivan Shumkov <ivanshumkov@gmail.com> Co-authored-by: PastaPastaPasta <6443210+PastaPastaPasta@users.noreply.github.com> Co-authored-by: pasta <pasta@dashboost.org> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Summary by CodeRabbit
New Features
Improvements
Chores