From 62ef3873f6ae82d5fa510a6b0eadde9d77f92da2 Mon Sep 17 00:00:00 2001 From: Jonathan Tzeng Date: Thu, 27 Aug 2026 18:49:05 -0700 Subject: [PATCH] Make MAX and multi-recipient send exclusive MAX spends the entire spendable balance, which only has a coherent meaning for a single recipient. The send scene now hides the MAX button whenever the send has more than one spend target, and withholds the "Add another address" row while a MAX amount is set, so the two can no longer be combined into a transaction that always fails with insufficient funds. --- CHANGELOG.md | 2 ++ src/components/scenes/SendScene2.tsx | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68120eca1f7..88fc4cb718f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased (develop) +- fixed: Hide the send scene's MAX button once a send has more than one recipient, and hide "Add another address" once MAX has been applied, so the two can no longer combine into an insufficient-funds transaction. + ## 4.51.0 (staging) - added: Push info-server attestation tokens into edge-core-js via `setAttestationToken` so the login server can skip CAPTCHA for attested devices, and allow `LOGIN_SERVER` / `INFO_SERVER` env overrides for local E2E stacks. diff --git a/src/components/scenes/SendScene2.tsx b/src/components/scenes/SendScene2.tsx index 050a7e8ddf2..1232d6bed4d 100644 --- a/src/components/scenes/SendScene2.tsx +++ b/src/components/scenes/SendScene2.tsx @@ -620,6 +620,11 @@ const SendComponent: React.FC = props => { const handleFlipInputModal = (index: number, spendTarget: EdgeSpendTarget) => (): void => { const { noChangeMiningFee } = getSpecialCurrencyInfo(pluginId) + // A max spend only has a defined meaning for a single recipient: it + // consumes the entire spendable balance. Once the send has more than one + // target there is nothing left over for the others, so the button is + // hidden rather than allowed to produce an insufficient-funds spend. + const isMultipleTargets = spendInfo.spendTargets.length > 1 Airship.show(bridge => ( = props => { startNativeAmount={spendTarget.nativeAmount} feeTokenId={null} forceField={fieldChanged} + hideMaxButton={isMultipleTargets} onAmountsChanged={handleAmountsChanged(spendTarget)} onMaxSet={() => { setMaxSpendSetter(index) @@ -753,7 +759,11 @@ const SendComponent: React.FC = props => { hiddenFeaturesMap.address === true || hiddenFeaturesMap.amount === true || lockTilesMap.address === true || - lockTilesMap.amount === true + lockTilesMap.amount === true || + // The existing target already claims the whole spendable balance, so a + // second recipient could only ever be funded by shrinking it. Withhold + // the entry point instead of silently discarding the max amount. + maxSpendSetter >= 0 ) { return null }