Skip to content

Commit

Permalink
feat(dashpay): add coinjoin error handling to enter amount screen (#1247
Browse files Browse the repository at this point in the history
)

* feat: add coinjoin error handling on enter amount screen

* refactor: create InsufficientCoinJoinMoneyException for dry run exception handling
  • Loading branch information
HashEngineering authored Jan 23, 2024
1 parent add3638 commit eac2283
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 11 deletions.
1 change: 1 addition & 0 deletions common/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
<string name="exchange_rate_template" translatable="false">%1$s DASH = %2$s</string>
<string name="send_coins_error_dusty_send">The amount is too small to send</string>
<string name="send_coins_error_insufficient_money">Insufficient funds</string>
<string name="send_coins_error_insufficient_mixed_money">Insufficient mixed funds. Wait for CoinJoin mixing to finish or disable this feature in the settings to complete this transaction.</string>
<string name="syncing">Syncing</string>
<string name="no_connection">No internet connection</string>
<string name="rate_not_available">Not available</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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])

Expand Down
14 changes: 9 additions & 5 deletions wallet/src/de/schildbach/wallet/ui/send/SendCoinsFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
}
Expand All @@ -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
Expand Down
13 changes: 9 additions & 4 deletions wallet/src/de/schildbach/wallet/ui/send/SendCoinsViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -124,6 +123,8 @@ class SendCoinsViewModel @Inject constructor(
val contactData: LiveData<UsernameSearchResult>
get() = _contactData

private var coinJoinMode: CoinJoinMode = CoinJoinMode.NONE

init {
blockchainStateDao.observeState()
.filterNotNull()
Expand All @@ -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 ->
Expand Down Expand Up @@ -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
}
}
Expand Down

0 comments on commit eac2283

Please sign in to comment.