Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-09 15:16:51 +03:00
commit 2e6647fa50
19 changed files with 74 additions and 32 deletions

@ -1 +1 @@
Subproject commit 8c4d938121710f20c16d111b1171805d96aa5b98
Subproject commit 9f34ca0ea3969b5ba6b82e1aea2fef0a44463fc8

View file

@ -11,6 +11,7 @@ import com.tangem.core.decompose.navigation.Route
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.feedback.models.WalletMetaInfo
import com.tangem.domain.markets.TokenMarketParams
import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.scan.ScanResponse

View file

@ -23,21 +23,24 @@ import com.tangem.core.ui.components.ResizableText
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.format.bigdecimal.anyDecimals
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.BaseAmountBlockTestTags
import java.math.BigDecimal
@Composable
fun AmountBlock(amountState: AmountState, isClickDisabled: Boolean, isEditingDisabled: Boolean, onClick: () -> Unit) {
if (amountState !is AmountState.Data) return
val amount = amountState.amountTextField
val cryptoAmount = formatWithSymbol(amount.value, amount.cryptoAmount.currencySymbol)
val cryptoAmount = amount.cryptoAmount.value.format {
crypto(
symbol = amount.cryptoAmount.currencySymbol,
decimals = amount.cryptoAmount.decimals,
)
}
val fiatAmount = amount.fiatAmount.value.format {
fiat(
fiatCurrencySymbol = amount.fiatAmount.currencySymbol,
@ -93,9 +96,6 @@ fun AmountBlock(amountState: AmountState, isClickDisabled: Boolean, isEditingDis
}
}
fun formatWithSymbol(amount: String, symbol: String) =
BigDecimal.ZERO.format { crypto(symbol, 0).anyDecimals() }.replace("0", amount)
// region Preview
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -46,6 +46,7 @@ internal object BlockchainSDKConfigConverter : Converter<EnvironmentConfigModel,
moralisApiKey = value.moralisApiKey,
etherscanApiKey = value.etherScanApiKey,
blinkApiKey = value.blinkApiKey,
tatumApiKey = value.tatumApiKey,
)
}

View file

@ -46,6 +46,7 @@ class EnvironmentConfigModel(
@Json(name = "etherscanApiKey") val etherScanApiKey: String?,
@Json(name = "yieldModuleApiKey") val yieldModuleApiKey: String?,
@Json(name = "blinkApiKey") val blinkApiKey: String?,
@Json(name = "tatumApiKey") val tatumApiKey: String?,
)
@JsonClass(generateAdapter = true)

View file

@ -132,7 +132,7 @@
<string name="biometric_unavailable_warning">Du hast die biometrische Authentifizierung auf deinem Telefon deaktiviert und kannst keine Wallets in der App speichern. Um Wallets zu speichern, aktiviere bitte die biometrische Authentifizierung in deinen Telefoneinstellungen.</string>
<string name="bitcoin_promo_activation_error">Bei der Bearbeitung Deines Aktionscodes ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.</string>
<string name="bitcoin_promo_activation_error_title">Fehler bei der Aktivierung</string>
<string name="bitcoin_promo_activation_success">Dein Promo-Code wurde erfolgreich aktiviert. Ein Bonus von 10 USDT in Bitcoin wird Deinem Konto innerhalb von 14 Tagen gutgeschrieben.</string>
<string name="bitcoin_promo_activation_success">Ihr Aktionscode wurde erfolgreich aktiviert. Eine Belohnung wird innerhalb von 14 Tagen auf Ihr Konto gutgeschrieben.</string>
<string name="bitcoin_promo_activation_success_title">Promo-Code aktiviert</string>
<string name="bitcoin_promo_already_activated">Dieser Aktionscode wurde bereits verwendet und kann nicht erneut aktiviert werden.</string>
<string name="bitcoin_promo_already_activated_title">Code nicht verfügbar</string>

View file

@ -80,7 +80,7 @@
<string name="biometric_unavailable_warning">Ha desactivado la autenticación biométrica en su teléfono y no podrá guardar billeteras en la aplicación. Para guardar billeteras, active la función de autenticación biométrica en los ajustes de su teléfono.</string>
<string name="bitcoin_promo_activation_error">Se produjo un error al procesar tu código promocional. Inténtalo de nuevo más tarde.</string>
<string name="bitcoin_promo_activation_error_title">Error de activación</string>
<string name="bitcoin_promo_activation_success">Su código promocional se ha activado correctamente. Un bono de 10 USDT en Bitcoin se abonará en su cuenta en un plazo de 14 días.</string>
<string name="bitcoin_promo_activation_success">Tu código promocional se activó correctamente. Una recompensa se acreditará en tu cuenta dentro de 14 días.</string>
<string name="bitcoin_promo_activation_success_title">Código promocional activado</string>
<string name="bitcoin_promo_already_activated">Este código promocional ya ha sido utilizado y no puede activarse de nuevo.</string>
<string name="bitcoin_promo_already_activated_title">Código no disponible</string>

View file

@ -62,7 +62,7 @@
<string name="biometric_unavailable_warning">Vous avez désactivé l\'authentification biométrique sur votre téléphone et ne pourrez pas enregistrer de portefeuilles dans l\'application. Pour enregistrer des portefeuilles, veuillez activer la fonction d\'authentification biométrique dans les paramètres de votre téléphone.</string>
<string name="bitcoin_promo_activation_error">Une erreur s\'est produite lors du traitement de votre code promo. Veuillez réessayer plus tard.</string>
<string name="bitcoin_promo_activation_error_title">Erreur d\'activation</string>
<string name="bitcoin_promo_activation_success">Votre code promo a été activé avec succès. Un bonus de 10 USDT en Bitcoin sera crédité dans 14 jours.</string>
<string name="bitcoin_promo_activation_success">Votre code promotionnel a été activé avec succès. Une récompense sera créditée sur votre compte dans un délai de 14 jours.</string>
<string name="bitcoin_promo_activation_success_title">Code promo activé</string>
<string name="bitcoin_promo_already_activated">Ce code promo a déjà été utilisé et ne peut pas être activé à nouveau.</string>
<string name="bitcoin_promo_already_activated_title">Code indisponible</string>

View file

@ -134,7 +134,7 @@
<string name="biometric_unavailable_warning">お使いの携帯電話で生体認証が無効になっているため、アプリにウォレットを保存できません。ウォレットを保存するには、携帯電話の設定で生体認証機能を有効にしてください。</string>
<string name="bitcoin_promo_activation_error">プロモーションコードの処理中にエラーが発生しました。しばらくしてからもう一度お試しください。</string>
<string name="bitcoin_promo_activation_error_title">アクティベーションエラー</string>
<string name="bitcoin_promo_activation_success">プロモーションコードが正常に有効化されました。14日以内に10 USDT相当のビットコインがアカウントに入金されます。</string>
<string name="bitcoin_promo_activation_success">プロモコードが正常に有効化されました。リワードは14日以内にあなたのアカウントに付与されます。</string>
<string name="bitcoin_promo_activation_success_title">プロモーションコードが有効になりました</string>
<string name="bitcoin_promo_already_activated">このプロモーションコードは既に使用されているため、再度使うことはできません。</string>
<string name="bitcoin_promo_already_activated_title">コードが利用できません</string>

View file

@ -61,7 +61,7 @@
<string name="biometric_unavailable_warning">Ви вимкнули біометричну автентифікацію на своєму телефоні і не зможете зберігати гаманці в додатку. Щоб зберегти гаманці, будь ласка, увімкніть функцію біометричної автентифікації в налаштуваннях телефону.</string>
<string name="bitcoin_promo_activation_error">Під час обробки промокоду сталася помилка. Будь ласка, спробуйте пізніше.</string>
<string name="bitcoin_promo_activation_error_title">Помилка активації</string>
<string name="bitcoin_promo_activation_success">Ваш промокод успішно активовано. Бонус 10 USDT у Bitcoin буде зараховано через 14 днів.</string>
<string name="bitcoin_promo_activation_success">Ваш промокод було успішно активовано. Винагороду буде зараховано на ваш рахунок протягом 14 днів.</string>
<string name="bitcoin_promo_activation_success_title">Промокод активовано</string>
<string name="bitcoin_promo_already_activated">Цей промокод уже був використаний і не може бути активований повторно.</string>
<string name="bitcoin_promo_already_activated_title">Код недоступний</string>

View file

@ -137,6 +137,12 @@ internal class DefaultTransactionRepository(
): TransactionData.Uncompiled = withContext(dispatchers.io) {
val blockchain = network.toBlockchain()
val walletManager = walletManagersFacade.getOrCreateWalletManager(
userWalletId = userWalletId,
blockchain = blockchain,
derivationPath = network.derivationPath.value,
) ?: error("Wallet manager not found")
val extras = createTransactionDataExtras(
callData = SmartContractCallDataProviderFactory.getApprovalCallData(
spenderAddress = spenderAddress,
@ -148,15 +154,23 @@ internal class DefaultTransactionRepository(
gasLimit = null,
)
return@withContext createTransaction(
amount = amount,
fee = fee,
memo = null,
destination = contractAddress,
userWalletId = userWalletId,
network = network,
txExtras = extras,
)
return@withContext if (fee != null) {
walletManager.createTransaction(
amount = amount,
fee = fee,
destination = contractAddress,
).copy(
extras = extras,
)
} else {
TransactionData.Uncompiled(
amount = amount,
sourceAddress = walletManager.wallet.address,
destinationAddress = contractAddress,
extras = extras,
fee = null,
)
}
}
override suspend fun createNFTTransferTransaction(

View file

@ -32,6 +32,8 @@ sealed class DestinationTextFieldUM {
// if value is human-readable address, this field contains the actual brief blockchain address
val briefBlockchainAddress: String?
get() = blockchainAddress?.toBriefAddressFormat(BRIEF_ADDRESS_EDGE_LENGTH, BRIEF_ADDRESS_EDGE_LENGTH)
val isAddressEns = blockchainAddress != null
}
data class RecipientMemo(

View file

@ -24,6 +24,7 @@ internal sealed class SendAnalyticEvents(
val feeType: AnalyticsParam.FeeType,
val blockchain: String,
val nonceNotEmpty: Boolean,
private val ensStatus: AnalyticsParam.EnsStatus,
) : SendAnalyticEvents(
event = "Transaction Sent Screen Opened",
params = mapOf(
@ -31,7 +32,10 @@ internal sealed class SendAnalyticEvents(
FEE_TYPE to feeType.value,
BLOCKCHAIN to blockchain,
NONCE to nonceNotEmpty.toString().capitalize(),
ENS_ADDRESS to (blockchain == "Ethereum").toString(),
ENS_ADDRESS to when (ensStatus) {
AnalyticsParam.EnsStatus.EMPTY -> false.toString().capitalize()
AnalyticsParam.EnsStatus.FULL -> true.toString().capitalize()
},
),
)

View file

@ -27,6 +27,7 @@ internal class SendAnalyticHelper @Inject constructor(
feeType = feeType,
blockchain = cryptoCurrency.network.name,
nonceNotEmpty = feeSelectorUM.feeNonce is FeeNonce.Nonce,
ensStatus = getEnsStatus(sendUM),
),
)
analyticsEventHandler.send(
@ -51,4 +52,14 @@ internal class SendAnalyticHelper @Inject constructor(
else -> Basic.TransactionSent.MemoType.Null
}
}
private fun getEnsStatus(sendUM: SendUM): AnalyticsParam.EnsStatus {
val blockchainAddressForEns =
(sendUM.destinationUM as? DestinationUM.Content)?.addressTextField?.isAddressEns
return if (blockchainAddressForEns == true) {
AnalyticsParam.EnsStatus.FULL
} else {
AnalyticsParam.EnsStatus.EMPTY
}
}
}

View file

@ -56,15 +56,20 @@ import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.send.analytics.SendAnalyticHelper
import com.tangem.features.send.v2.send.confirm.SendConfirmComponent
import com.tangem.features.send.v2.send.confirm.model.transformers.*
import com.tangem.features.send.v2.send.confirm.model.transformers.SendConfirmInitialStateTransformer
import com.tangem.features.send.v2.send.confirm.model.transformers.SendConfirmSendingStateTransformer
import com.tangem.features.send.v2.send.confirm.model.transformers.SendConfirmSentStateTransformer
import com.tangem.features.send.v2.send.confirm.model.transformers.SendConfirmationNotificationsTransformerV2
import com.tangem.features.send.v2.send.ui.state.SendUM
import com.tangem.features.send.v2.subcomponents.amount.SendAmountReduceTrigger
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.orZero
import com.tangem.utils.extensions.stripZeroPlainString
import com.tangem.utils.transformer.update
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.math.BigDecimal
import javax.inject.Inject
@ -422,12 +427,14 @@ internal class SendConfirmModel @Inject constructor(
val userWalletId = receivingUserWallet.userWalletId ?: return
val network = receivingUserWallet.network ?: return
modelScope.launch {
addCryptoCurrenciesUseCase(
userWalletId = userWalletId,
cryptoCurrency = cryptoCurrency,
network = network,
)
modelScope.launch(dispatchers.default) {
withContext(NonCancellable) {
addCryptoCurrenciesUseCase(
userWalletId = userWalletId,
cryptoCurrency = cryptoCurrency,
network = network,
)
}
}
}

View file

@ -220,7 +220,7 @@ internal class SendDestinationModel @Inject constructor(
async {
val addresses = if (!wallet.isMultiCurrency) {
getCryptoCurrencyUseCase(wallet.walletId).getOrNull()?.let {
if (it.network.id == cryptoCurrencyNetwork.id) {
if (it.network.rawId == cryptoCurrencyNetwork.rawId) {
getNetworkAddressesUseCase.invokeSync(
userWalletId = wallet.walletId,
networkRawId = it.network.id.rawId,

View file

@ -5,7 +5,7 @@
# https://github.com/tangem/tangem-sdk-android/
# https://github.com/tangem/vico
tangemBlockchainSdk = "develop-1259"
tangemBlockchainSdk = "develop-1263"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-564"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^

View file

@ -26,4 +26,5 @@ internal enum class ProviderTypeIdMapping(val id: String, val providerType: Prov
KoinosPro(id = "koinospro", providerType = ProviderType.Koinos.KoinosPro),
AlephiumTangem(id = "tangemAlephium", providerType = ProviderType.Alephium.Tangem),
Blink(id = "blink", providerType = ProviderType.Blink),
Tatum(id = "tatum", providerType = ProviderType.Kusama.Tatum),
}

@ -1 +1 @@
Subproject commit 5fe6eee2e37743769a0392711515486c7cbe63ff
Subproject commit 888c626fc514542c3d7568b83d8afe92777b1e0c