Updated on 2026-08-14

This commit is contained in:
Tangem 2020-09-22 01:30:48 +03:00
parent 5448004713
commit 6eee63c0d4
8 changed files with 53 additions and 41 deletions

View file

@ -64,7 +64,7 @@ dependencies {
implementation 'com.google.android.material:material:1.2.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
implementation 'com.tangem:blockchain:1.35.0'
implementation 'com.tangem:blockchain:1.37.0'
//lifecycle
implementation "androidx.lifecycle:lifecycle-runtime:2.2.0"

View file

@ -1,7 +1,6 @@
package com.tangem.tap.features.send.redux.middlewares
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.TransactionError
import com.tangem.common.extensions.isZero
import com.tangem.tap.common.redux.AppState
@ -41,11 +40,7 @@ class AmountMiddleware {
if (inputValue.isZero() && amountState.amountToSendCrypto.isZero()) return
val inputValueCrypto = if (amountState.mainCurrency.type == MainCurrencyType.CRYPTO) inputValue
else when (amountState.typeOfAmount) {
AmountType.Coin -> sendState.convertFiatToCoin(inputValue)
AmountType.Token -> sendState.convertFiatToToken(inputValue)
else -> inputValue
}
else sendState.convertFiatToExtractCrypto(inputValue)
dispatch(AmountAction.SetAmount(inputValueCrypto, true))
dispatch(AmountActionUi.CheckAmountToSend)
@ -54,6 +49,7 @@ class AmountMiddleware {
private fun checkAmountToSend(appState: AppState?, dispatch: (Action) -> Unit) {
val sendState = appState?.sendState ?: return
val walletManager = sendState.walletManager ?: return
val typedAmount = sendState.amountState.amountToExtract ?: return
val inputCrypto = sendState.amountState.amountToSendCrypto
if (sendState.amountState.viewAmountValue.value == "0" && inputCrypto.isZero()) {
@ -62,12 +58,8 @@ class AmountMiddleware {
return
}
val feeCrypto = sendState.feeState.getCurrentFee()
val feeAmount = Amount(feeCrypto, walletManager.wallet.blockchain)
val totalAmount = Amount(sendState.getTotalAmountToSend(inputCrypto), walletManager.wallet.blockchain)
val transactionErrors = walletManager.validateTransaction(totalAmount, feeAmount)
val amountToSend = Amount(typedAmount, sendState.getTotalAmountToSend(inputCrypto))
val transactionErrors = walletManager.validateTransaction(amountToSend, sendState.feeState.currentFee)
if (transactionErrors.isEmpty()) {
dispatch(AmountAction.SetAmountError(null))
} else {

View file

@ -20,6 +20,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.rekotlin.Action
import org.rekotlin.Middleware
import timber.log.Timber
/**
[REDACTED_AUTHOR]
@ -43,10 +44,9 @@ private fun verifyAndSendTransaction(appState: AppState?, dispatch: (Action) ->
val walletManager = appState.globalState.scanNoteResponse?.walletManager ?: return
val recipientAddress = sendState.addressPayIdState.recipientWalletAddress ?: return
val typedAmount = sendState.amountState.amountToExtract ?: return
val feeAmount = sendState.feeState.currentFee ?: return
val feeAmount = Amount(sendState.feeState.getCurrentFee(), walletManager.wallet.blockchain)
val totalToSend = sendState.getTotalAmountToSend()
val amountToSend = Amount(typedAmount.currencySymbol, totalToSend, recipientAddress, typedAmount.decimals, typedAmount.type)
val amountToSend = Amount(typedAmount, sendState.getTotalAmountToSend())
val verifyResult = walletManager.validateTransaction(amountToSend, feeAmount)
if (verifyResult.isNotEmpty()) {
@ -57,6 +57,7 @@ private fun verifyAndSendTransaction(appState: AppState?, dispatch: (Action) ->
dispatch(SendAction.ChangeSendButtonState(SendButtonState.PROGRESS))
val txData = walletManager.createTransaction(amountToSend, feeAmount, recipientAddress)
scope.launch {
walletManager.update()
val result = (walletManager as TransactionSender).send(txData, Signer(tangemSdk))
withContext(Dispatchers.Main) {
when (result) {
@ -76,6 +77,7 @@ private fun verifyAndSendTransaction(appState: AppState?, dispatch: (Action) ->
// user was cancelled the operation by closing the Sdk bottom sheet
}
else -> {
Timber.e(result.error)
dispatch(SendAction.SendError(TapError.BlockchainInternalError))
}
}

View file

@ -30,8 +30,8 @@ class AmountReducer : SendInternalReducer {
when (val currency = if (currencyCanBeSwitched) action.mainCurrency else MainCurrencyType.CRYPTO) {
MainCurrencyType.FIAT -> {
val fiatToSend = if (state.amountToSendCrypto.isZero()) BigDecimal.ZERO
else sendState.convertCoinToFiat(state.amountToSendCrypto)
val rescaledBalance = sendState.convertCoinToFiat(state.balanceCrypto, true)
else sendState.convertExtractCryptoToFiat(state.amountToSendCrypto)
val rescaledBalance = sendState.convertExtractCryptoToFiat(state.balanceCrypto, true)
state.copy(
viewAmountValue = InputViewValue(fiatToSend.stripZeroPlainString()),
viewBalanceValue = rescaledBalance.stripZeroPlainString(),
@ -61,7 +61,7 @@ class AmountReducer : SendInternalReducer {
val result = when (action) {
is AmountAction.SetAmount -> {
val amount = if (state.mainCurrency.type == MainCurrencyType.CRYPTO) action.amountCrypto
else sendState.convertCoinToFiat(action.amountCrypto, true)
else sendState.convertExtractCryptoToFiat(action.amountCrypto, true)
state.copy(
viewAmountValue = InputViewValue(amount.stripZeroPlainString(), action.isUserInput),
amountToSendCrypto = action.amountCrypto,

View file

@ -15,10 +15,13 @@ import java.math.BigDecimal
*/
class ReceiptReducer : SendInternalReducer {
companion object {
const val EMPTY = "-"
}
private lateinit var sendState: SendState
private lateinit var amountState: AmountState
private lateinit var feeState: FeeState
private val EMPTY = "-"
override fun handle(action: SendScreenAction, sendState: SendState): SendState {
this.sendState = sendState
@ -50,7 +53,7 @@ class ReceiptReducer : SendInternalReducer {
}
private fun createFiatType(symbols: ReceiptSymbols, showBlank: Boolean): ReceiptFiat {
val feeCrypto = feeState.getCurrentFee()
val feeCrypto = feeState.getCurrentFeeValue()
val feeFiat = convertToFiatPrecision(feeCrypto)
if (showBlank) {
@ -82,7 +85,7 @@ class ReceiptReducer : SendInternalReducer {
}
private fun createCryptoType(symbols: ReceiptSymbols, showBlank: Boolean): ReceiptCrypto {
val feeCrypto = feeState.getCurrentFee()
val feeCrypto = feeState.getCurrentFeeValue()
val feeFiat = convertToFiatPrecision(feeCrypto)
if (showBlank) {
return ReceiptCrypto("0", feeCrypto.stripZeroPlainString(), "0", "0", "0", symbols)
@ -111,7 +114,7 @@ class ReceiptReducer : SendInternalReducer {
}
private fun createTokenFiatType(symbols: ReceiptSymbols, showBlank: Boolean): ReceiptTokenFiat {
val feeCoin = feeState.getCurrentFee()
val feeCoin = feeState.getCurrentFeeValue()
if (showBlank) {
val feeFiat = convertToFiatPrecision(feeCoin)
return ReceiptTokenFiat("0", feeFiat, "0", "0", "0", symbols)
@ -124,9 +127,9 @@ class ReceiptReducer : SendInternalReducer {
val amountFiat = sendState.tokenConverter!!.toFiatUnscaled(tokensToSend)
val totalFiat = amountFiat.plus(feeFiat)
ReceiptTokenFiat(
amountFiat = amountFiat.scaleToFiat().stripZeroPlainString(),
feeFiat = feeFiat.stripZeroPlainString(),
totalFiat = totalFiat.scaleToFiat().stripZeroPlainString(),
amountFiat = amountFiat.scaleToFiat(true).stripZeroPlainString(),
feeFiat = feeFiat.scaleToFiat(true).stripZeroPlainString(),
totalFiat = totalFiat.scaleToFiat(true).stripZeroPlainString(),
willSentToken = tokensToSend.stripZeroPlainString(),
willSentFeeCoin = feeCoin.stripZeroPlainString(),
symbols = symbols
@ -144,7 +147,7 @@ class ReceiptReducer : SendInternalReducer {
}
private fun createTokenCryptoType(symbols: ReceiptSymbols, showBlank: Boolean): ReceiptTokenCrypto {
val feeCoin = feeState.getCurrentFee()
val feeCoin = feeState.getCurrentFeeValue()
if (showBlank) {
return ReceiptTokenCrypto("0", feeCoin.stripZeroPlainString(), "0", symbols)
}
@ -158,7 +161,7 @@ class ReceiptReducer : SendInternalReducer {
ReceiptTokenCrypto(
amountToken = tokensToSend.stripZeroPlainString(),
feeCoin = feeCoin.stripZeroPlainString(),
totalFiat = totalFiat.scaleToFiat().stripZeroPlainString(),
totalFiat = totalFiat.scaleToFiat(true).stripZeroPlainString(),
symbols = symbols
)
} else {

View file

@ -27,5 +27,5 @@ data class FeeState(
fun isReady(): Boolean = error == null && currentFee != null
fun getCurrentFee(): BigDecimal = currentFee?.value ?: BigDecimal.ZERO
fun getCurrentFeeValue(): BigDecimal = currentFee?.value ?: BigDecimal.ZERO
}

View file

@ -56,6 +56,11 @@ data class SendState(
else coinConverter!!.toCrypto(value)
}
fun convertFiatToToken(value: BigDecimal): BigDecimal {
return if (!this.tokenIsConvertible()) value
else tokenConverter!!.toCrypto(value)
}
fun convertCoinToFiat(value: BigDecimal, scaleWithPrecision: Boolean = false): BigDecimal {
if (!this.coinIsConvertible()) return value
@ -63,11 +68,6 @@ data class SendState(
return if (!scaleWithPrecision) converter.toFiat(value) else converter.toFiatWithPrecision(value)
}
fun convertFiatToToken(value: BigDecimal): BigDecimal {
return if (!this.tokenIsConvertible()) value
else tokenConverter!!.toCrypto(value)
}
fun convertTokenToFiat(value: BigDecimal, scaleWithPrecision: Boolean = false): BigDecimal {
if (!this.tokenIsConvertible()) return value
@ -75,11 +75,25 @@ data class SendState(
return if (!scaleWithPrecision) converter.toFiat(value) else converter.toFiatWithPrecision(value)
}
fun convertFiatToExtractCrypto(fiatValue: BigDecimal): BigDecimal = when (amountState.typeOfAmount) {
AmountType.Coin -> convertFiatToCoin(fiatValue)
AmountType.Token -> convertFiatToToken(fiatValue)
AmountType.Reserve -> fiatValue
}
fun convertExtractCryptoToFiat(cryptoValue: BigDecimal, scaleWithPrecision: Boolean = false): BigDecimal {
return when (amountState.typeOfAmount) {
AmountType.Coin -> convertCoinToFiat(cryptoValue, scaleWithPrecision)
AmountType.Token -> convertTokenToFiat(cryptoValue, scaleWithPrecision)
AmountType.Reserve -> cryptoValue
}
}
fun getButtonState(): SendButtonState = if (isReadyToSend()) SendButtonState.ENABLED else SendButtonState.DISABLED
fun getTotalAmountToSend(value: BigDecimal = amountState.amountToSendCrypto): BigDecimal {
val needToExtractFee = amountState.isCoinAmount() && feeState.feeIsIncluded
return if (needToExtractFee) value.minus(feeState.getCurrentFee()) else value
return if (needToExtractFee) value.minus(feeState.getCurrentFeeValue()) else value
}
fun coinIsConvertible(): Boolean = coinConverter != null

View file

@ -15,6 +15,7 @@ import com.tangem.tap.domain.assembleErrorIds
import com.tangem.tap.features.send.BaseStoreFragment
import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction.Error
import com.tangem.tap.features.send.redux.FeeAction
import com.tangem.tap.features.send.redux.reducers.ReceiptReducer
import com.tangem.tap.features.send.redux.states.*
import com.tangem.tap.features.send.ui.FeeUiHelper
import com.tangem.tap.features.send.ui.SendFragment
@ -183,6 +184,8 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
fun getString(id: Int): String = mainLayout.context.getString(id)
val rough = getString(R.string.sign_rough)
fun roughOrEmpty(value: String): String = if (value == ReceiptReducer.EMPTY) value else "$rough $value"
when (state.visibleTypeOfReceipt) {
ReceiptLayoutType.FIAT -> {
val receipt = state.fiat ?: return
@ -191,7 +194,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
totalTokenLayout.show(false)
fg.tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}")
fg.tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}")
totalLayout.tvTotalValue.update("$rough ${receipt.totalFiat} ${receipt.symbols.fiat}")
totalLayout.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}")
val willSent = SpannableStringBuilder()
.bold { append(receipt.willSentCrypto) }.append(" ")
@ -211,8 +214,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
val willSent = SpannableStringBuilder()
.bold {
append(rough).append(" ")
append(receipt.willSentFiat).append(" ")
append(roughOrEmpty(receipt.willSentFiat)).append(" ")
append(receipt.symbols.fiat)
append(" (fee: ${receipt.feeFiat} ")
append(receipt.symbols.fiat).append(")")
@ -226,7 +228,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
totalTokenLayout.show(false)
fg.tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}")
fg.tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}")
totalLayout.tvTotalValue.update("${receipt.totalFiat} ${receipt.symbols.fiat}")
totalLayout.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}")
val willSent = SpannableStringBuilder()
.bold {
@ -252,8 +254,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
val willSent = SpannableStringBuilder()
.bold {
append(getString(R.string.sign_rough)).append(" ")
append(receipt.totalFiat).append(" ")
append(roughOrEmpty(receipt.totalFiat)).append(" ")
append(receipt.symbols.fiat)
}
totalTokenLayout.tvTotalTokenCryptoValue.update(willSent.toString())