diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml
index c3b972d2dc..f7d13355d1 100644
--- a/common/src/main/res/values/strings.xml
+++ b/common/src/main/res/values/strings.xml
@@ -83,6 +83,7 @@
%1$s DASH = %2$s
The amount is too small to send
Insufficient funds
+ Insufficient mixed funds. Wait for CoinJoin mixing to finish or disable this feature in the settings to complete this transaction.
Syncing
No internet connection
Not available
diff --git a/integrations/crowdnode/src/test/java/org/dash/wallet/integrations/crowdnode/CrowdNodeTxFilterTest.kt b/integrations/crowdnode/src/test/java/org/dash/wallet/integrations/crowdnode/CrowdNodeTxFilterTest.kt
index ef4c221f15..680bc5beb3 100644
--- a/integrations/crowdnode/src/test/java/org/dash/wallet/integrations/crowdnode/CrowdNodeTxFilterTest.kt
+++ b/integrations/crowdnode/src/test/java/org/dash/wallet/integrations/crowdnode/CrowdNodeTxFilterTest.kt
@@ -228,10 +228,10 @@ class CrowdNodeTxFilterTest {
on { isPubKeyHashMine(any(), any()) } doReturn true
}
- val connectedData = "0100000001a144eb2405271f2a56332ba40e61c4248a42c45dbc7ca453c5ac6bd1ca13f4ed170000006b483045022100a84e01ee3b13b6056d3a2e3ae2e000aa08897f6b8769c149ae940ad0d348305702207f494646bf8789610d2a44642dbf3136519c93c0a97df885ae8fba81848361850121022bc500272dc2263fda23e4ccd99d39942ad92127e8d43581876038c9b9014517ffffffff03409c0000000000001976a9147b5bea31861a1cfca6cb5cb93277fb7515bda7df88acabc55101000000001976a91486c1305dc7b556051ef2f3c1a7f8671f1abc349988ac8016a437000000001976a914ae0621debab253e792f2558dd1889b5c29110dff88ac00000000"
+ val connectedData = "0100000001a144eb2405271f2a56332ba40e61c4248a42c45dbc7ca453c5ac6bd1ca13f4ed170000006b483045022100a84e01ee3b13b6056d3a2e3ae2e000aa08897f6b8769c149ae940ad0d348305702207f494646bf8789610d2a44642dbf3136519c93c0a97df885ae8fba81848361850121022bc500272dc2263fda23e4ccd99d39942ad92127e8d43581876038c9b9014517ffffffff03409c0000000000001976a9147b5bea31861a1cfca6cb5cb93277fb7515bda7df88acabc55101000000001976a91486c1305dc7b556051ef2f3c1a7f8671f1abc349988ac8016a437000000001976a914ae0621debab253e792f2558dd1889b5c29110dff88ac00000000" // ktlint-disable max-line-length
val connectedTx = Transaction(networkParams, Utils.HEX.decode(connectedData))
- val txData = "01000000017f8b38abf42bce8bfbfc9c5965096a9cfed3ef0a1fc7fe8a79881a90a393a790020000006a47304402203545c3a1ee67fef9f4733caa38619affd92e012271b01078a7eb80b179c56355022040ad74e6521c659104aec47621f7c8cf8defd1eb1c3f5484ada3b124cad4454a01210221a2fb697857eeb83d47a57050f27a38c84958ce7b79741d7f686c2867a4a895ffffffff03224e0000000000001976a914197b4429f61bdb64a859567b441a23e6630d533588ac224e0000000000001976a914f850a88d4f515ea7b92908ad4d08e7383922ca0988ac3779a337000000001976a914b658c3dac62e4c570b08cf317fb70436ea37870088ac00000000"
+ val txData = "01000000017f8b38abf42bce8bfbfc9c5965096a9cfed3ef0a1fc7fe8a79881a90a393a790020000006a47304402203545c3a1ee67fef9f4733caa38619affd92e012271b01078a7eb80b179c56355022040ad74e6521c659104aec47621f7c8cf8defd1eb1c3f5484ada3b124cad4454a01210221a2fb697857eeb83d47a57050f27a38c84958ce7b79741d7f686c2867a4a895ffffffff03224e0000000000001976a914197b4429f61bdb64a859567b441a23e6630d533588ac224e0000000000001976a914f850a88d4f515ea7b92908ad4d08e7383922ca0988ac3779a337000000001976a914b658c3dac62e4c570b08cf317fb70436ea37870088ac00000000" // ktlint-disable max-line-length
val internalTx = Transaction(networkParams, Utils.HEX.decode(txData))
internalTx.inputs[0].connect(connectedTx.outputs[0])
diff --git a/wallet/src/de/schildbach/wallet/ui/send/SendCoinsFragment.kt b/wallet/src/de/schildbach/wallet/ui/send/SendCoinsFragment.kt
index e8508ad2f3..f7f1de2f9e 100644
--- a/wallet/src/de/schildbach/wallet/ui/send/SendCoinsFragment.kt
+++ b/wallet/src/de/schildbach/wallet/ui/send/SendCoinsFragment.kt
@@ -24,6 +24,7 @@ import android.net.Uri
import android.os.Bundle
import android.view.View
import android.widget.Toast
+import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
@@ -174,11 +175,8 @@ class SendCoinsFragment: Fragment(R.layout.send_coins_fragment) {
} else if (dryRunException != null) {
errorMessage = when (dryRunException) {
is Wallet.DustySendRequested -> getString(R.string.send_coins_error_dusty_send)
- is InsufficientMoneyException -> if (!requirePinForBalance || userAuthorizedDuring) {
- getString(R.string.send_coins_error_insufficient_money)
- } else {
- ""
- }
+ is InsufficientCoinJoinMoneyException -> getErrorMessage(R.string.send_coins_error_insufficient_mixed_money)
+ is InsufficientMoneyException -> getErrorMessage(R.string.send_coins_error_insufficient_money)
is Wallet.CouldNotAdjustDownwards -> getString(R.string.send_coins_error_dusty_send)
else -> dryRunException.toString()
}
@@ -201,6 +199,12 @@ class SendCoinsFragment: Fragment(R.layout.send_coins_fragment) {
)
}
+ private fun getErrorMessage(@StringRes errorMessage: Int) = if (!requirePinForBalance || userAuthorizedDuring) {
+ getString(errorMessage)
+ } else {
+ ""
+ }
+
private suspend fun authenticateOrConfirm() {
if (!viewModel.everythingPlausible()) {
return
diff --git a/wallet/src/de/schildbach/wallet/ui/send/SendCoinsViewModel.kt b/wallet/src/de/schildbach/wallet/ui/send/SendCoinsViewModel.kt
index 205ddbd1ae..eaded63b88 100644
--- a/wallet/src/de/schildbach/wallet/ui/send/SendCoinsViewModel.kt
+++ b/wallet/src/de/schildbach/wallet/ui/send/SendCoinsViewModel.kt
@@ -39,9 +39,7 @@ import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onEach
-import org.bitcoinj.coinjoin.CoinJoinCoinSelector
import org.bitcoinj.core.Address
import org.bitcoinj.core.Coin
import org.bitcoinj.core.InsufficientMoneyException
@@ -59,6 +57,7 @@ import javax.inject.Inject
import kotlin.math.min
class SendException(message: String) : Exception(message)
+class InsufficientCoinJoinMoneyException(ex: InsufficientMoneyException) : InsufficientMoneyException(ex.missing, "${ex.message} [coinjoin]")
@HiltViewModel
class SendCoinsViewModel @Inject constructor(
@@ -124,6 +123,8 @@ class SendCoinsViewModel @Inject constructor(
val contactData: LiveData
get() = _contactData
+ private var coinJoinMode: CoinJoinMode = CoinJoinMode.NONE
+
init {
blockchainStateDao.observeState()
.filterNotNull()
@@ -134,11 +135,11 @@ class SendCoinsViewModel @Inject constructor(
coinJoinConfig.observeMode()
.map { mode ->
+ coinJoinMode = mode
if (mode == CoinJoinMode.NONE) {
MaxOutputAmountCoinSelector()
} else {
MaxOutputAmountCoinJoinCoinSelector(wallet)
- // MaxOutputAmountCoinSelector()
}
}
.flatMapLatest { coinSelector ->
@@ -298,7 +299,11 @@ class SendCoinsViewModel @Inject constructor(
dryrunSendRequest = sendRequest
_dryRunSuccessful.value = true
} catch (ex: Exception) {
- dryRunException = ex
+ dryRunException = if (ex is InsufficientMoneyException && coinJoinMode != CoinJoinMode.NONE && !currentAmount.isGreaterThan(wallet.getBalance(MaxOutputAmountCoinSelector()))) {
+ InsufficientCoinJoinMoneyException(ex)
+ } else {
+ ex
+ }
_dryRunSuccessful.value = false
}
}