Updated on 2026-08-14

This commit is contained in:
Tangem 2024-06-11 09:19:53 +01:00
commit 80ec72c173
14 changed files with 97 additions and 28 deletions

@ -1 +1 @@
Subproject commit 4424b32de5a80305cd3ca6eca219b09a16e940c5
Subproject commit a837db27973dca80e51cf9590eb34e060bed1236

View file

@ -89,19 +89,19 @@ class AdditionalFeedbackInfo {
fun updateOnSendError(
walletManager: WalletManager,
amountToSend: Amount,
amountToSend: Amount?,
feeAmount: Amount?,
destinationAddress: String,
destinationAddress: String?,
) {
onSendErrorWalletInfo = createEmailWalletInfo(walletManager)
this.destinationAddress = destinationAddress
amount = amountToSend.value?.stripZeroPlainString() ?: "0"
this.destinationAddress = destinationAddress ?: "0"
amount = amountToSend?.value?.stripZeroPlainString() ?: "0"
fee = if (feeAmount != null) {
feeAmount.value?.stripZeroPlainString() ?: "0"
} else {
"Unable to receive"
}
token = if (amountToSend.type is AmountType.Token) amountToSend.currencySymbol else ""
token = if (amountToSend?.type is AmountType.Token) amountToSend.currencySymbol else ""
}
private fun createEmailWalletInfo(walletManager: WalletManager): EmailWalletInfo {

View file

@ -1,11 +1,16 @@
package com.tangem.tap.common.redux.legacy
import com.tangem.domain.redux.LegacyAction
import com.tangem.domain.tokens.utils.convertToAmount
import com.tangem.tap.common.extensions.inject
import com.tangem.tap.common.feedback.RateCanBeBetterEmail
import com.tangem.tap.common.feedback.SendTransactionFailedEmail
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.scope
import com.tangem.tap.store
import kotlinx.coroutines.launch
import org.rekotlin.Middleware
internal object LegacyMiddleware {
@ -22,9 +27,29 @@ internal object LegacyMiddleware {
)
}
is LegacyAction.SendEmailTransactionFailed -> {
store.state.globalState.feedbackManager?.sendEmail(
SendTransactionFailedEmail(action.errorMessage),
)
if (store.inject(DaggerGraphState::feedbackManagerFeatureToggles).isLocalLogsEnabled) {
store.state.globalState.feedbackManager?.sendEmail(
SendTransactionFailedEmail(action.errorMessage),
)
} else {
scope.launch {
store.inject(DaggerGraphState::walletManagersFacade)
.getOrCreateWalletManager(
userWalletId = action.userWalletId,
network = action.cryptoCurrency.network,
)?.let { walletManager ->
store.state.globalState.feedbackManager?.infoHolder?.updateOnSendError(
walletManager = walletManager,
amountToSend = action.amount?.convertToAmount(action.cryptoCurrency),
feeAmount = action.fee?.convertToAmount(action.cryptoCurrency),
destinationAddress = action.destinationAddress,
)
}
store.state.globalState.feedbackManager?.sendEmail(
SendTransactionFailedEmail(action.errorMessage),
)
}
}
}
}
next(action)

View file

@ -6,6 +6,7 @@ import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors
/**
@ -22,7 +23,7 @@ object Analytics : GlobalAnalyticsEventHandler {
private val analyticsScope: CoroutineScope by lazy { createScope() }
private val handlers = mutableMapOf<String, AnalyticsHandler>()
private val paramsInterceptors = mutableMapOf<String, ParamsInterceptor>()
private val paramsInterceptors = ConcurrentHashMap<String, ParamsInterceptor>()
private val analyticsFilters = mutableSetOf<AnalyticsEventFilter>()
private val analyticsMutex = Mutex()

View file

@ -21,11 +21,11 @@
},
{
"name": "WC_SOLANA_TX_SIGN_ENABLED",
"version": "5.11.0"
"version": "undefined"
},
{
"name": "TOKEN_LIST_LCE_ENABLED",
"version": "5.11.0"
"version": "5.12.0"
},
{
"name": "CARDANO_TOKENS_SUPPORT_ENABLED",

View file

@ -668,7 +668,7 @@
<string name="warning_access_denied_message">Используйте %s или отсканируйте карту, чтобы разблокировать доступ к вашему кошельку</string>
<string name="warning_backup_errors_message">Пожалуйста, выведите все средства из этого кошелька, сбросьте его к заводским настройкам и создайте новый. Доступ к текущему кошельку будет утерян.</string>
<string name="warning_backup_errors_title">Ошибка активации</string>
<string name="warning_beacon_chain_retirement_content">По решению разработчиков сети BNB, стандарт BEP-2 перестанет поддерживаться в июне 2024 года. Чтобы не потерять свои активы, их необходимо преобразовать в стандарт BEP-20. Используйте функцию обмена в приложении чтобы перевести их в cеть BNB Smart Chain.</string>
<string name="warning_beacon_chain_retirement_content">По решению разработчиков сети BNB стандарт BEP-2 перестанет поддерживаться в июне 2024 года. Чтобы не потерять активы, их необходимо преобразовать в стандарт BEP-20. Используйте функцию обмена в приложении или сторонние сервисы, чтобы перевести средства в cеть BNB Smart Chain.</string>
<string name="warning_beacon_chain_retirement_title">Отключение сети BNB Beacon Chain</string>
<string name="warning_button_could_be_better">Можно лучше</string>
<string name="warning_button_like_it">Нравится</string>

View file

@ -661,7 +661,7 @@
<string name="warning_access_denied_message">Use %s or scan a card to unlock access to your wallet</string>
<string name="warning_backup_errors_message">Please withdraw all funds from this wallet, reset it to factory settings, and create a new one. Access to the current wallet will be lost.</string>
<string name="warning_backup_errors_title">Activation error</string>
<string name="warning_beacon_chain_retirement_content">According to BNB network developers, support for the BEP-2 standard will end in June 2024. To avoid losing assets with this standard, please convert them to the BEP-20 standard. Use our swap service to transfer them to the BNB Smart Chain network.</string>
<string name="warning_beacon_chain_retirement_content">According to BNB network developers, support for the BEP-2 standard will end in June 2024. To avoid losing assets with this standard, please convert them to the BEP-20 standard. Use our swap service or third-party services to transfer funds to the BNB Smart Chain network.</string>
<string name="warning_beacon_chain_retirement_title">BNB Beacon Chain will shut down</string>
<string name="warning_button_could_be_better">Could be better</string>
<string name="warning_button_like_it">Like it</string>

View file

@ -1,7 +1,10 @@
package com.tangem.domain.redux
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import org.rekotlin.Action
import java.math.BigDecimal
sealed interface LegacyAction : Action {
@ -16,6 +19,20 @@ sealed interface LegacyAction : Action {
/**
* Sending an email to support when sending transaction failed
*
* @param cryptoCurrency current currency
* @param userWalletId selected user wallet id
* @param amount sending amount
* @param fee spending fee
* @param destinationAddress recipient address
* @param errorMessage sending error
*/
data class SendEmailTransactionFailed(val errorMessage: String) : LegacyAction
data class SendEmailTransactionFailed(
val cryptoCurrency: CryptoCurrency,
val userWalletId: UserWalletId,
val amount: BigDecimal?,
val fee: BigDecimal?,
val destinationAddress: String?,
val errorMessage: String,
) : LegacyAction
}

View file

@ -1,5 +1,6 @@
package com.tangem.features.send.impl.presentation.state.recipient
import com.tangem.common.extensions.isZero
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
@ -39,7 +40,8 @@ internal class SendRecipientHistoryListConverter(
} else {
item.sourceType is TxHistoryItem.SourceType.Single
}
isTransfer && isSingleAddress && isNotContract
val notZero = !item.amount.isZero()
isTransfer && isSingleAddress && isNotContract && item.isOutgoing && notZero
}
.take(RECENT_LIST_SIZE)
.mapIndexed { index, tx ->

View file

@ -442,6 +442,7 @@ internal class SendViewModel @Inject constructor(
getFixedTxHistoryItemsUseCase.getSync(
userWalletId = userWalletId,
currency = cryptoCurrency,
pageSize = RECENT_TX_SIZE,
).getOrElse { emptyList() }
}
uiState = recipientStateFactory.onLoadedHistoryList(txHistory = txHistoryList)
@ -530,7 +531,31 @@ internal class SendViewModel @Inject constructor(
}
override fun onFailedTxEmailClick(errorMessage: String) {
reduxStateHolder.dispatch(LegacyAction.SendEmailTransactionFailed(errorMessage))
val recipient = uiState.recipientState?.addressTextField?.value
val feeValue = uiState.feeState?.fee?.amount?.value
val amountValue = uiState.amountState?.amountTextField?.cryptoAmount?.value
val receivingAmount = if (amountValue != null && feeValue != null) {
checkAndCalculateSubtractedAmount(
isAmountSubtractAvailable = isAmountSubtractAvailable,
cryptoCurrencyStatus = cryptoCurrencyStatus,
amountValue = amountValue,
feeValue = feeValue,
reduceAmountBy = uiState.sendState?.reduceAmountBy ?: BigDecimal.ZERO,
)
} else {
null
}
reduxStateHolder.dispatch(
LegacyAction.SendEmailTransactionFailed(
cryptoCurrency = cryptoCurrency,
userWalletId = userWalletId,
amount = receivingAmount,
fee = feeValue,
destinationAddress = recipient,
errorMessage = errorMessage,
),
)
}
override fun onTokenDetailsClick(userWalletId: UserWalletId, currency: CryptoCurrency) =
@ -981,6 +1006,7 @@ internal class SendViewModel @Inject constructor(
const val CHECK_FEE_UPDATE_DELAY = 60_000L
const val BALANCE_UPDATE_DELAY = 11_000L
const val RECENT_LOAD_DELAY = 500L
const val RECENT_TX_SIZE = 100
const val RU_LOCALE = "ru"
const val EN_LOCALE = "en"

View file

@ -2,6 +2,7 @@ package com.tangem.feature.swap.domain.models
import com.tangem.utils.toFormattedString
import java.math.BigDecimal
import java.math.RoundingMode
data class SwapAmount(
val value: BigDecimal,
@ -39,10 +40,5 @@ fun createFromAmountWithOffset(amountWithOffset: String, decimals: Int): SwapAmo
@Throws(IllegalStateException::class)
fun SwapAmount.toStringWithRightOffset(): String {
return value.movePointRight(decimals).toPlainString()
}
@Throws(IllegalStateException::class)
fun SwapAmount.toStringWithLeftOffset(): String {
return value.movePointLeft(decimals).toPlainString()
return value.setScale(decimals, RoundingMode.HALF_DOWN).movePointRight(decimals).toPlainString()
}

View file

@ -5,6 +5,10 @@ import com.tangem.feature.swap.domain.models.ui.FeeType
sealed class FeeItemState {
/**
* @param amountCrypto - crypto amount formatted with symbol
* @param amountFiatFormatted - formatted fiat amount
*/
data class Content(
val feeType: FeeType,
val title: TextReference,

View file

@ -471,9 +471,7 @@ internal class StateBuilder(
warnings.add(
SwapWarning.GeneralWarning(
createNetworkFeeCoverageNotificationConfig(
quoteModel.fromTokenInfo.tokenAmount.getFormattedCryptoAmount(
quoteModel.fromTokenInfo.cryptoCurrencyStatus.currency,
),
fee.feeCryptoFormatted,
fee.feeFiatFormatted,
),
),
@ -578,7 +576,7 @@ internal class StateBuilder(
warnings.add(getWarningForError(dataError, fromToken.cryptoCurrencyStatus.currency))
if (includeFeeInAmount is IncludeFeeInAmount.Included && uiStateHolder.fee is FeeItemState.Content) {
val feeCoverageNotification = createNetworkFeeCoverageNotificationConfig(
fromToken.tokenAmount.getFormattedCryptoAmount(fromToken.cryptoCurrencyStatus.currency),
uiStateHolder.fee.amountCrypto,
uiStateHolder.fee.amountFiatFormatted,
)
warnings.add(SwapWarning.GeneralWarning(feeCoverageNotification))

View file

@ -87,7 +87,7 @@ markdown = "0.7.2"
# endregion Other libraries
# region Tangem
tangemBlockchainSdk = "release-app_5.12-664"
tangemBlockchainSdk = "release-app_5.12-667"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "release-app_5.12-364"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^