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, )