From 8b1329aa4b2e94ae1c9bb4f9123c121c540bf6a3 Mon Sep 17 00:00:00 2001
From: yvebe <14962060+yvebe@users.noreply.github.com>
Date: Tue, 26 Nov 2024 11:01:31 +0200
Subject: [PATCH] Add Polkadot gas fees & existenial deposit reaping warning
(#1404)
---
.../ui/models/send/SendFormViewModel.kt | 45 ++++++++++++++++++-
.../wallet/ui/screens/send/SendFormScreen.kt | 18 ++++++++
app/src/main/res/values/strings.xml | 1 +
.../data/chains/helpers/PolkadotHelper.kt | 5 +++
.../com/vultisig/wallet/data/models/Coin.kt | 24 +++++-----
.../data/repositories/GasFeeRepository.kt | 3 +-
6 files changed, 82 insertions(+), 14 deletions(-)
diff --git a/app/src/main/java/com/vultisig/wallet/ui/models/send/SendFormViewModel.kt b/app/src/main/java/com/vultisig/wallet/ui/models/send/SendFormViewModel.kt
index 7044096a1..3842dfc95 100644
--- a/app/src/main/java/com/vultisig/wallet/ui/models/send/SendFormViewModel.kt
+++ b/app/src/main/java/com/vultisig/wallet/ui/models/send/SendFormViewModel.kt
@@ -8,12 +8,14 @@ import androidx.compose.runtime.Immutable
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.vultisig.wallet.R
+import com.vultisig.wallet.data.chains.helpers.PolkadotHelper
import com.vultisig.wallet.data.models.Account
import com.vultisig.wallet.data.models.Address
import com.vultisig.wallet.data.models.AddressBookEntry
import com.vultisig.wallet.data.models.Chain
import com.vultisig.wallet.data.models.ChainId
import com.vultisig.wallet.data.models.Coin
+import com.vultisig.wallet.data.models.Coins
import com.vultisig.wallet.data.models.FiatValue
import com.vultisig.wallet.data.models.GasFeeParams
import com.vultisig.wallet.data.models.ImageModel
@@ -93,6 +95,7 @@ internal data class SendFormUiModel(
val showGasFee: Boolean = true,
val dstAddressError: UiText? = null,
val tokenAmountError: UiText? = null,
+ val reapingError: UiText? = null,
val hasMemo: Boolean = false,
val showGasSettings: Boolean = false,
val specific: BlockChainSpecificAndUtxo? = null,
@@ -193,6 +196,7 @@ internal class SendFormViewModel @Inject constructor(
calculateGasFees()
calculateSpecific()
collectAdvanceGasUi()
+ collectAmountChecks()
}
fun loadData(
@@ -786,7 +790,6 @@ internal class SendFormViewModel @Inject constructor(
accounts,
) { token, accounts ->
val address = token.address
- val showGasFee = !token.allowZeroGas()
val hasMemo = token.isNativeToken
val uiModel = accountToTokenBalanceUiModelMapper.map(SendSrc(
@@ -807,7 +810,6 @@ internal class SendFormViewModel @Inject constructor(
it.copy(
from = address,
selectedCoin = uiModel,
- showGasFee = showGasFee,
hasMemo = hasMemo,
)
}
@@ -846,6 +848,45 @@ internal class SendFormViewModel @Inject constructor(
}
}
+ private fun collectAmountChecks() {
+ viewModelScope.launch {
+ combine(
+ selectedToken.filterNotNull(),
+ tokenAmountFieldState.textAsFlow(),
+ gasFee.filterNotNull(),
+ ) { selectedToken, tokenAmount, gasFee ->
+ val selectedAccount = selectedAccount
+ if (selectedAccount != null &&
+ selectedToken.chain == Chain.Polkadot &&
+ selectedToken.ticker == Coins.polkadot.ticker
+ ) {
+ val balance = selectedAccount.tokenValue
+ ?.value
+ ?: BigInteger.ZERO
+ val tokenAmountInt = tokenAmount.toString()
+ .toBigDecimalOrNull()
+ ?.movePointRight(selectedToken.decimal)
+ ?.toBigInteger()
+ ?: BigInteger.ZERO
+
+ if (balance - (gasFee.value + tokenAmountInt) <
+ PolkadotHelper.DEFAULT_EXISTENTIAL_DEPOSIT.toBigInteger()
+ ) {
+ uiState.update {
+ it.copy(
+ reapingError = UiText.StringResource(R.string.send_form_polka_reaping_warning)
+ )
+ }
+ } else {
+ uiState.update {
+ it.copy(reapingError = null)
+ }
+ }
+ }
+ }.collect()
+ }
+ }
+
private suspend fun convertValue(
value: String,
transform: (
diff --git a/app/src/main/java/com/vultisig/wallet/ui/screens/send/SendFormScreen.kt b/app/src/main/java/com/vultisig/wallet/ui/screens/send/SendFormScreen.kt
index 7754e34cc..43cacde71 100644
--- a/app/src/main/java/com/vultisig/wallet/ui/screens/send/SendFormScreen.kt
+++ b/app/src/main/java/com/vultisig/wallet/ui/screens/send/SendFormScreen.kt
@@ -1,5 +1,6 @@
package com.vultisig.wallet.ui.screens.send
+import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -282,6 +283,23 @@ internal fun SendFormScreen(
}
)
}
+
+ AnimatedContent(
+ targetState = state.reapingError,
+ label = "error message"
+ ) { errorMessage ->
+ if (errorMessage != null) {
+ Column {
+ UiSpacer(size = 8.dp)
+ Text(
+ text = errorMessage.asString(),
+ color = Theme.colors.error,
+ style = Theme.menlo.body1
+ )
+ }
+ }
+ }
+
UiSpacer(size = 80.dp)
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3886ac7c8..e91f8a428 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -484,4 +484,5 @@
Skip Password
Please use \"Skip Password\" to save without password
Network connection lost. Please check your internet connection
+ Ensure you leave enough funds to cover the fees. If an account balance falls below 1 DOT (Existential Deposit), the account will be deactivated (reaped) and any remaining funds will be lost. You can reactivate the address with a new deposit larger than the existential deposit at any time. However, this will not recover the lost funds.
\ No newline at end of file
diff --git a/data/src/main/kotlin/com/vultisig/wallet/data/chains/helpers/PolkadotHelper.kt b/data/src/main/kotlin/com/vultisig/wallet/data/chains/helpers/PolkadotHelper.kt
index 0aed01ef3..35530db07 100644
--- a/data/src/main/kotlin/com/vultisig/wallet/data/chains/helpers/PolkadotHelper.kt
+++ b/data/src/main/kotlin/com/vultisig/wallet/data/chains/helpers/PolkadotHelper.kt
@@ -96,4 +96,9 @@ class PolkadotHelper(
)
)
}
+
+ companion object {
+ const val DEFAULT_FEE_PLANCKS = 250_000_000L
+ const val DEFAULT_EXISTENTIAL_DEPOSIT = 10_000_000_000L // 1 DOT
+ }
}
\ No newline at end of file
diff --git a/data/src/main/kotlin/com/vultisig/wallet/data/models/Coin.kt b/data/src/main/kotlin/com/vultisig/wallet/data/models/Coin.kt
index 01883cab8..0fc40227d 100644
--- a/data/src/main/kotlin/com/vultisig/wallet/data/models/Coin.kt
+++ b/data/src/main/kotlin/com/vultisig/wallet/data/models/Coin.kt
@@ -51,6 +51,18 @@ object Coins {
contractAddress = "",
isNativeToken = true,
)
+ val polkadot = Coin(
+ chain = Chain.Polkadot,
+ ticker = "DOT",
+ logo = "dot",
+ address = "",
+ decimal = 10,
+ hexPublicKey = "",
+ priceProviderID = "polkadot",
+ contractAddress = "",
+ isNativeToken = true,
+ )
+
val SupportedCoins = listOf(
wewe,
Coin(
@@ -1451,17 +1463,7 @@ object Coins {
contractAddress = "",
isNativeToken = true,
),
- Coin(
- chain = Chain.Polkadot,
- ticker = "DOT",
- logo = "dot",
- address = "",
- decimal = 10,
- hexPublicKey = "",
- priceProviderID = "polkadot",
- contractAddress = "",
- isNativeToken = true,
- ),
+ polkadot,
Coin(
chain = Chain.ZkSync,
ticker = "ETH",
diff --git a/data/src/main/kotlin/com/vultisig/wallet/data/repositories/GasFeeRepository.kt b/data/src/main/kotlin/com/vultisig/wallet/data/repositories/GasFeeRepository.kt
index 821ccafe0..0dd26aeb9 100644
--- a/data/src/main/kotlin/com/vultisig/wallet/data/repositories/GasFeeRepository.kt
+++ b/data/src/main/kotlin/com/vultisig/wallet/data/repositories/GasFeeRepository.kt
@@ -5,6 +5,7 @@ import com.vultisig.wallet.data.api.EvmApiFactory
import com.vultisig.wallet.data.api.SolanaApi
import com.vultisig.wallet.data.api.ThorChainApi
import com.vultisig.wallet.data.api.chains.SuiApi
+import com.vultisig.wallet.data.chains.helpers.PolkadotHelper
import com.vultisig.wallet.data.chains.helpers.SolanaHelper.Companion.DefaultFeeInLamports
import com.vultisig.wallet.data.crypto.ThorChainHelper
import com.vultisig.wallet.data.models.Chain
@@ -113,7 +114,7 @@ internal class GasFeeRepositoryImpl @Inject constructor(
Chain.Polkadot -> {
val nativeToken = tokenRepository.getNativeToken(chain.id)
TokenValue(
- value = 0.toBigInteger(),
+ value = PolkadotHelper.DEFAULT_FEE_PLANCKS.toBigInteger(),
unit = chain.feeUnit,
decimals = nativeToken.decimal,
)