Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3493f71
fix(wallets): use selector ceiling for asset-lock Max
lklimek Jul 27, 2026
807bad5
docs: changelog entry for #929 Max fix
lklimek Jul 27, 2026
6bed93f
fix(wallets): use the real height watermark in the asset-lock ceiling…
lklimek Jul 27, 2026
c2abaa4
refactor(wallets): replace the asset-lock ceiling binary search with …
lklimek Jul 27, 2026
fcd4c0f
Merge branch 'v1.0-dev' into fix/929-max-shield-snapshot-balance
lklimek Jul 27, 2026
40938d1
fix(wallets): close asset-lock ceiling gaps found by CI review
lklimek Jul 27, 2026
e96f20f
fix(ui): migrate remaining asset-lock funding flows to the builder ce…
lklimek Jul 27, 2026
aa53542
docs: correct #929 changelog entry to match the fixed scope
lklimek Jul 27, 2026
e8d2c26
Merge remote-tracking branch 'origin/fix/929-max-shield-snapshot-bala…
lklimek Jul 27, 2026
8d6f1c9
Merge branch 'v1.0-dev' into fix/929-max-shield-snapshot-balance
lklimek Jul 28, 2026
7ec1505
docs(wallet_backend): document accepted risk from upstream rust-dashc…
lklimek Jul 28, 2026
d38b544
fix(wallet_backend): shrink asset-lock probe's write-lock scope, docu…
lklimek Jul 28, 2026
d02fd53
fix(ui): harden AssetLockBalanceCache against generation regression a…
lklimek Jul 28, 2026
64cd544
fix(ui): reserve fees for Identity sends, bound ReceiveDeposit by its…
lklimek Jul 28, 2026
48e457f
test(send_screen): seed the asset-lock cache in the Core->Platform ki…
lklimek Jul 28, 2026
0d0e762
docs: correct the Max-fix changelog entry and add its user story
lklimek Jul 28, 2026
c127b38
fix(ui): reserve the identity fee at dispatch-time validation, not ju…
lklimek Jul 29, 2026
45c5a0b
fix(ui): debounce the asset-lock probe on no-op events, stop dropping…
lklimek Jul 29, 2026
4d7a3e3
fix(ui): bound ReceiveDeposit dispatch by its address, fix the deboun…
lklimek Jul 29, 2026
85e9f46
fix(wallet_backend): bound the asset-lock probe's worst-case wait wit…
lklimek Jul 29, 2026
d652f8f
docs: note the asset-lock probe's timeout in the Max-fix changelog entry
lklimek Jul 29, 2026
33622bb
fix(wallet_backend): remove BnB timeout workaround, close stale-valid…
lklimek Jul 30, 2026
1bc0d96
chore(deps): bump dashpay/platform pin to include the BnB feasibility…
lklimek Jul 30, 2026
03ec120
docs: drop implementation-detail sentence from the Max-fix changelog …
lklimek Jul 30, 2026
8f5c140
fix(wallet_backend): correlate asset-lock probes by request id, disti…
lklimek Jul 30, 2026
4e826bc
fix(wallet): close asset-lock quote freshness gaps from round-5's loc…
lklimek Jul 30, 2026
792e50e
Merge remote-tracking branch 'origin/v1.0-dev' into fix/929-max-shiel…
lklimek Jul 30, 2026
bb5234a
Merge remote-tracking branch 'origin/v1.0-dev' into fix/929-max-shiel…
lklimek Jul 30, 2026
4a61f3e
fix(wallet): close round-8 blocking gaps in the asset-lock Max probe …
lklimek Jul 30, 2026
9a5105d
fix(wallet): keep asset-lock Max usable on dust wallets and stop the …
lklimek Jul 30, 2026
c4a985f
docs(wallet): correct stale reserved-outpoint claim in observation do…
lklimek Jul 30, 2026
8ea190d
Merge remote-tracking branch 'origin/v1.0-dev' into fix/929-max-shiel…
lklimek Jul 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Comment thread
Claudius-Maginificent marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

### Fixed

- **"Max" now matches what your Core wallet can actually send**: pressing
"Max" when shielding DASH, funding a Platform address, sending directly to
an identity, or funding an identity (creating or topping up, from your
wallet balance or a received deposit) could suggest an amount larger than
the wallet could actually send, so the transaction was rejected no matter
how you adjusted it. Max and the amount check now ask the wallet directly
what it can send instead of estimating from an on-screen balance, so the
two stay in agreement, and both reserve room for the fee. Funding from a
received deposit is also now capped by what actually arrived at that
deposit address, never by unrelated funds elsewhere in the wallet. While
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
the check is running, the amount field shows "Checking the available
amount…"; if it fails, "The available amount could not be checked."
appears with a "Retry available amount check" button, and you can still
switch to a different funding method at any point. For a very large
wallet, this check is capped at a few seconds; if it can't finish in
time, the amount field explains that and suggests sending a smaller
amount or trying again shortly.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: The changelog overpromises absolute sendability

The entry says Max matches what the wallet can actually send, Max and validation stay in agreement, and the large-wallet check is capped at a few seconds. The cache currently validates against stale ceilings after wallet-input changes, and the timeout still waits for an active BranchAndBound call to finish. A builder quote is also inherently a point-in-time result whose reservation state can change before dispatch. Rephrase the changelog and SND-017 as a builder-derived point-in-time ceiling that reduces over-limit attempts, and claim a bounded wait only after the backend actually returns at the deadline.

source: ['codex']


- **Wallet rename consistency**: renaming a wallet no longer overwrites other
saved wallet details when metadata cannot be read. Overlapping renames and
wallet removals also keep displayed aliases and deleted-wallet metadata
Expand Down
9 changes: 9 additions & 0 deletions docs/user-stories.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,15 @@ As a developer, I want to transfer credits privately from my shielded pool to an
- Spending is paused until the shielded balance is verified, and the button is disabled with a clear reason while verification is in progress.
- Available only on Platform protocol v12 or later when Expert view or Developer view is selected.

### SND-017: "Max" is verified against what the wallet can actually build [Implemented]
**Persona:** Alex, Priya, Jordan

As a user, I want "Max" (and the amount check behind it) to reflect what my Core wallet can genuinely send when shielding DASH, funding a Platform address, sending directly to an identity, or funding an identity from my wallet balance, so that the amount I'm offered — or type in myself — never gets rejected for exceeding what the wallet can build.

- "Max" and amount validation both ask the wallet directly for its actual sendable ceiling, reserving the relevant operation's fee, instead of estimating from the on-screen balance — the two always agree, including for an amount typed in by hand rather than produced by the Max button.
- While the check is running, the amount field shows "Checking the available amount…"; if it fails, "The available amount could not be checked." appears with a "Retry available amount check" button.
- Funding from a received deposit is capped by what actually arrived at that specific deposit address, never by unrelated funds elsewhere in the wallet — see SND-014 (Core-to-Core Max), which uses a separate, simpler network-fee-only calculation not covered by this story.

---

## Asset Locks (ALK)
Expand Down
18 changes: 18 additions & 0 deletions src/backend_task/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//! `Debug` → variant name + fields (logged and shown in collapsible details).

use crate::model::fee_estimation::format_credits_as_dash;
use crate::model::wallet::WalletSeedHash;
use dash_sdk::Error as SdkError;
use dash_sdk::dapi_client::DapiClientError;
use dash_sdk::dapi_client::transport::TransportError;
Expand Down Expand Up @@ -234,6 +235,23 @@ pub enum TaskError {
>,
},

/// The non-broadcasting asset-lock builder probe exceeded its bounded wait.
#[error(
"We couldn't work out the maximum amount you can send from this wallet in time. Try sending a smaller amount, or wait a few minutes and try again."
)]
AssetLockMaxAmountTimedOut { seed_hash: WalletSeedHash },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: Timeout guidance recommends an action the UI still blocks

After this error, each screen marks the quote request as failed, and all affected dispatch paths still require asset_lock_balance.get(...) to return a loaded ceiling. Entering a smaller amount cannot bypass that prerequisite, so the suggested action cannot send anything. Direct users to the visible Retry control or to wait and retry the check.

Suggested change
/// The non-broadcasting asset-lock builder probe exceeded its bounded wait.
#[error(
"We couldn't work out the maximum amount you can send from this wallet in time. Try sending a smaller amount, or wait a few minutes and try again."
)]
AssetLockMaxAmountTimedOut { seed_hash: WalletSeedHash },
/// The non-broadcasting asset-lock builder probe exceeded its bounded wait.
#[error(
"We couldn't check how much this wallet can send in time. Select \"Retry available amount check\", or wait a few minutes and try again."
)]
AssetLockMaxAmountTimedOut { seed_hash: WalletSeedHash },

source: ['codex']

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in 33622bb — Timeout guidance recommends an action the UI still blocks no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.


/// The non-broadcasting asset-lock builder probe could not determine a safe Max.
#[error(
"The wallet's available amount could not be checked. Wait a moment and try again."
)]
AssetLockBalanceQueryFailed {
#[source]
source: Box<
dash_sdk::dpp::key_wallet::wallet::managed_wallet_info::transaction_builder::BuilderError,
>,
},

/// The payment would need more individual unspent outputs than fit in a
/// single standard transaction.
#[error(
Expand Down
41 changes: 41 additions & 0 deletions src/backend_task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,11 @@ pub enum BackendTaskContext {
ScheduledVoteSweep { network: Network },
/// Receive-address derivation for one wallet's deposit flow.
GenerateReceiveAddress { seed_hash: WalletSeedHash },
/// Live asset-lock builder ceiling query for one wallet.
AssetLockMaxAmount {
seed_hash: WalletSeedHash,
snapshot_generation: u64,
},
/// One HD-wallet or imported-key alias update.
WalletRename(WalletTask),
/// A known backend task that needs no finer UI correlation.
Expand Down Expand Up @@ -387,6 +392,16 @@ impl BackendTaskContext {
}
}

pub(crate) fn asset_lock_max_amount_request(&self) -> Option<(WalletSeedHash, u64)> {
match self.operation() {
Self::AssetLockMaxAmount {
seed_hash,
snapshot_generation,
} => Some((*seed_hash, *snapshot_generation)),
_ => None,
}
}

pub(crate) fn wallet_rename_task(&self) -> Option<&WalletTask> {
match self.operation() {
Self::WalletRename(task) => Some(task),
Expand Down Expand Up @@ -434,6 +449,13 @@ impl From<&BackendTask> for BackendTaskContext {
seed_hash: *seed_hash,
}
}
BackendTask::WalletTask(WalletTask::GetAssetLockMaxAmount {
seed_hash,
snapshot_generation,
}) => Self::AssetLockMaxAmount {
seed_hash: *seed_hash,
snapshot_generation: *snapshot_generation,
},
BackendTask::WalletTask(
task @ (WalletTask::RenameHdWallet { .. }
| WalletTask::RenameSingleKeyWallet { .. }),
Expand Down Expand Up @@ -601,6 +623,12 @@ pub enum BackendTaskSuccessResult {
seed_hash: WalletSeedHash,
locks: Vec<platform_wallet::wallet::asset_lock::tracked::TrackedAssetLock>,
},
/// Largest asset-lock credit output the live upstream builder accepts.
AssetLockMaxAmount {
seed_hash: WalletSeedHash,
snapshot_generation: u64,
amount_duffs: u64,
},
/// Platform address balances fetched from Platform
PlatformAddressBalances {
seed_hash: WalletSeedHash,
Expand Down Expand Up @@ -1243,6 +1271,19 @@ impl AppContext {
.list_tracked_asset_locks(&seed_hash)
.await
.map(|locks| BackendTaskSuccessResult::TrackedAssetLocks { seed_hash, locks }),
WalletTask::GetAssetLockMaxAmount {
seed_hash,
snapshot_generation,
} => backend
.asset_lock_max_amount(&seed_hash)
.await
.map(
|amount_duffs| BackendTaskSuccessResult::AssetLockMaxAmount {
seed_hash,
snapshot_generation,
amount_duffs,
},
),
WalletTask::FetchPlatformAddressBalances { seed_hash } => {
self.fetch_platform_address_balances(seed_hash).await
}
Expand Down
6 changes: 6 additions & 0 deletions src/backend_task/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@ pub enum WalletTask {
ListTrackedAssetLocks {
seed_hash: WalletSeedHash,
},
/// Dry-run the live upstream asset-lock builder to obtain the largest
/// credit output its current UTXO set can fund.
GetAssetLockMaxAmount {
seed_hash: WalletSeedHash,
snapshot_generation: u64,
},
/// Fund Platform addresses from a tracked asset lock identified by its
/// credit-output outpoint. The proof and credit-output key are recovered
/// from the upstream `AssetLockManager` and the wallet's funding
Expand Down
14 changes: 14 additions & 0 deletions src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1461,6 +1461,20 @@ impl AppContext {
.unwrap_or_default()
}

/// Monotonic generation of the event-pushed snapshot for one wallet.
pub fn snapshot_generation(&self, seed_hash: &WalletSeedHash) -> u64 {
self.wallet_backend()
.map(|wb| wb.wallet_snapshot_generation(seed_hash))
.unwrap_or_default()
}

/// Snapshot generation and final-funds asset-lock signal from one read.
pub fn asset_lock_probe_snapshot(&self, seed_hash: &WalletSeedHash) -> (u64, u64) {
self.wallet_backend()
.map(|wallet_backend| wallet_backend.asset_lock_probe_snapshot(seed_hash))
.unwrap_or_default()
}

/// Number of UTXOs in the wallet's display snapshot. Used to estimate the
/// Core (L1) transaction fee for a "Max" send, which spends every UTXO.
///
Expand Down
18 changes: 16 additions & 2 deletions src/context/test_support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,34 @@ use crate::wallet_backend::DetKv;
/// to exercise the settings read-modify-write and feature-gate paths.
pub(crate) fn test_app_context(dir: &Path) -> Arc<AppContext> {
let app_kv = AppContext::open_app_kv(dir).expect("open app k/v");
test_app_context_with_kv(dir, app_kv)
test_app_context_with_kv_and_network(dir, app_kv, Network::Testnet)
}

/// Build a throwaway [`AppContext`] for a specific network.
pub(crate) fn test_app_context_for_network(dir: &Path, network: Network) -> Arc<AppContext> {
let app_kv = AppContext::open_app_kv(dir).expect("open app k/v");
test_app_context_with_kv_and_network(dir, app_kv, network)
}

/// [`test_app_context`] with a caller-supplied app k/v store, so a test can
/// inject a fault-injecting backing store (see `kv_test_support::FailingKv`).
pub(crate) fn test_app_context_with_kv(dir: &Path, app_kv: Arc<DetKv>) -> Arc<AppContext> {
test_app_context_with_kv_and_network(dir, app_kv, Network::Testnet)
}

fn test_app_context_with_kv_and_network(
dir: &Path,
app_kv: Arc<DetKv>,
network: Network,
) -> Arc<AppContext> {
crate::app_dir::ensure_env_file(dir);
let db = Arc::new(crate::database::Database::new(dir.join("data.db")).expect("db"));
db.create_tables(true).expect("create tables");
db.set_default_version().expect("set version");
let secret_store = AppContext::open_secret_store(dir).expect("open secret store");
AppContext::new(
dir.to_path_buf(),
Network::Testnet,
network,
db,
Default::default(),
Default::default(),
Expand Down
51 changes: 51 additions & 0 deletions src/model/asset_lock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//! Stateless asset-lock amount calculations shared by UI flows.

/// Why an asset-lock amount is outside the builder-derived ceiling.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AssetLockAmountError {
/// Adding the operation-specific reserve exceeded the amount range.
Overflow,
/// The requested amount plus its reserve exceeds the builder ceiling.
ExceedsMaximum { maximum_amount_duffs: u64 },
}

/// Largest user-entered amount after reserving operation-specific fees.
///
/// Both arguments must use the same unit (duffs or Platform credits).
pub fn asset_lock_user_max_amount(builder_max: u64, reserve: u64) -> u64 {
builder_max.saturating_sub(reserve)
}

/// Validate a user-entered amount against the live builder-derived ceiling.
pub fn validate_asset_lock_amount(
amount_duffs: u64,
reserve_duffs: u64,
builder_max_duffs: u64,
) -> Result<(), AssetLockAmountError> {
let required_duffs = amount_duffs
.checked_add(reserve_duffs)
.ok_or(AssetLockAmountError::Overflow)?;
if required_duffs > builder_max_duffs {
return Err(AssetLockAmountError::ExceedsMaximum {
maximum_amount_duffs: asset_lock_user_max_amount(builder_max_duffs, reserve_duffs),
});
}
Ok(())
}

#[cfg(test)]
mod tests {
use super::{AssetLockAmountError, asset_lock_user_max_amount, validate_asset_lock_amount};

#[test]
fn builder_ceiling_validation_reserves_operation_fee() {
assert_eq!(asset_lock_user_max_amount(10_000, 1_000), 9_000);
assert_eq!(validate_asset_lock_amount(9_000, 1_000, 10_000), Ok(()));
assert_eq!(
validate_asset_lock_amount(9_001, 1_000, 10_000),
Err(AssetLockAmountError::ExceedsMaximum {
maximum_amount_duffs: 9_000,
})
);
}
}
1 change: 1 addition & 0 deletions src/model/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod address;
pub mod amount;
pub mod asset_lock;
pub mod contested_name;
pub mod dashpay;
pub mod dashpay_derivation;
Expand Down
27 changes: 27 additions & 0 deletions src/ui/identities/add_new_identity_screen/by_receive_deposit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ impl AddNewIdentityScreen {
let mut action = AppAction::None;
self.reconcile_funding_deposit();
let step = *self.step.read_recover();
let seed_hash = self
.selected_wallet
.as_ref()
.and_then(|wallet| wallet.read().ok().map(|wallet| wallet.seed_hash()));

if step == WalletFundedScreenStep::WaitingOnFunds {
ui.heading(format!(
Expand All @@ -171,6 +175,29 @@ impl AddNewIdentityScreen {
// committed to the pending transaction, so the input's max recomputes to
// 0 and would show a stale "exceeds maximum" error over a succeeding op.
if step == WalletFundedScreenStep::FundsReceived {
let Some(seed_hash) = seed_hash else {
if ui.button("Choose a different funding method").clicked() {
self.reset_to_choose_funding();
}
return action;
};
if self.asset_lock_balance.is_failed(&seed_hash) {
ui.label("The available amount could not be checked.");
if ui.button("Retry available amount check").clicked() {
self.asset_lock_balance.invalidate_one(&seed_hash);
}
if ui.button("Choose a different funding method").clicked() {
self.reset_to_choose_funding();
}
return action;
}
if self.asset_lock_balance.get(&seed_hash).is_none() {
ui.label("Checking the available amount…");
if ui.button("Choose a different funding method").clicked() {
self.reset_to_choose_funding();
}
return action;
}
self.render_funding_amount_input(ui);

let has_valid_amount = self
Expand Down

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 RUST-005 · MEDIUM — the request/status block and the validate/report block are copy-pasted across three screens
(add_new_identity_screen/by_using_unused_balance.rs:102-126; top_up_identity_screen/by_using_unused_balance.rs:93-117; plus a third variant in send_screen.rs)

Two verbatim duplications and a third partial one.

Block A — 25 lines, byte-identical apart from the selected_wallet/wallet field name: resolve seed hash → read snapshot_generation → ensure_requested → failed branch with label and "Retry available amount check" button → not-loaded branch with "Checking the available amount…". send_screen carries a third, structurally different variant of the same logic split across request_asset_lock_max_amount and render_asset_lock_balance_status. That structural difference is not incidental — it is precisely why the three screens behave differently when the ceiling isn't loaded (RUST-001). The copies have already diverged once.

Block B — ~28 lines, verbatim: validate_asset_lock_amount(amount, 0, max_amount) → match error { Overflow => max_amount, ExceedsMaximum { maximum_amount_duffs } => maximum_amount_duffs } → MessageBanner::set_global(..) with the identical "You can transfer up to {} right now." string, duplicated between add_new_identity_screen/mod.rs:1061-1085 and top_up_identity_screen/mod.rs:481-505, with a Result<_, String> variant of the same shape in send_screen.rs:1675-1686.

Note the Overflow => max_amount fallback is hand-written at all four sites — and is unreachable at three of them, since they pass reserve_duffs = 0 and amount.checked_add(0) cannot overflow. The variant has no test coverage. An error type whose every consumer must write the same collapse is the wrong shape.

Fix:

  • Extract Block A into one helper on AssetLockBalanceCache (or funding_common) taking &mut Ui and returning a small Ready(u64) | Pending | Failed enum — each screen then decides layout only. This is also the cheapest way to land RUST-001's stale-while-revalidate change once rather than three times.
  • Collapse Block B by having the model yield the user-facing maximum directly — e.g. make AssetLockAmountError always carry maximum_amount_duffs — so no caller re-derives it. Then delete the Overflow arm, or cover it with a test.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed this is duplicated across the three funding screens, and your diagnosis that it's directly why the three screens drifted in behavior is exactly right. Deferring the full extraction as a larger refactor rather than doing it under this PR's scope, but the round of fixes just pushed did bring the three screens' patterns back into alignment with each other, which reduces (doesn't eliminate) the risk you're flagging.

🤖 Co-authored by Claudius the Magnificent AI Agent

Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ impl AddNewIdentityScreen {
}
};

let spendable_balance: u64 = self
.app_context
.snapshot_balance(&wallet.seed_hash())
.spendable();
let seed_hash = wallet.seed_hash();
let spendable_balance = self
.asset_lock_balance
.get(&seed_hash)
.unwrap_or_else(|| self.app_context.snapshot_balance(&seed_hash).spendable());

let dash_balance = spendable_balance as f64 * 1e-8; // Convert to DASH units

Expand All @@ -45,10 +46,7 @@ impl AddNewIdentityScreen {
fn render_insufficient_wallet_balance_banner(&self, ui: &mut egui::Ui) -> Option<AppAction> {
let selected_wallet = self.selected_wallet.as_ref()?;
let spendable_duffs = match selected_wallet.read() {
Ok(w) => self
.app_context
.snapshot_balance(&w.seed_hash())
.spendable(),
Ok(w) => self.asset_lock_balance.get(&w.seed_hash())?,
Err(_) => {
ui.label("Wallet is busy. Try again in a moment.");
return Some(AppAction::None);
Expand Down Expand Up @@ -102,8 +100,28 @@ impl AddNewIdentityScreen {
self.show_wallet_balance(ui);
ui.add_space(5.0);

let seed_hash = self
.selected_wallet
.as_ref()
.and_then(|wallet| wallet.read().ok().map(|wallet| wallet.seed_hash()));
let Some(seed_hash) = seed_hash else {
return action;
};
if self.asset_lock_balance.is_failed(&seed_hash) {
ui.label("The available amount could not be checked.");
if ui.button("Retry available amount check").clicked() {
self.asset_lock_balance.invalidate_one(&seed_hash);
}
return action;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
if self.asset_lock_balance.get(&seed_hash).is_none() {
ui.label("Checking the available amount…");
return action;
}

if let Some(insufficient_action) = self.render_insufficient_wallet_balance_banner(ui) {
return insufficient_action;
action |= insufficient_action;
return action;
}

self.render_funding_amount_input(ui);
Expand Down
Loading
Loading