diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt
index dd92464d2a..dedbd42301 100644
--- a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt
+++ b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt
@@ -401,6 +401,9 @@ class TokenItemStateConverter(
onYieldPromoCloseClick: (() -> Unit)?,
): TokenItemState.PromoBannerState {
val token = status.currency as? CryptoCurrency.Token ?: return TokenItemState.PromoBannerState.Empty
+ if (status.value !is CryptoCurrencyStatus.Loaded) {
+ return TokenItemState.PromoBannerState.Empty
+ }
if (yieldSupplyPromoBannerKey == null || yieldSupplyPromoBannerKey != token.yieldSupplyKey() ||
yieldModuleApyMap[token.yieldSupplyKey()] == null
) {
diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseError.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseError.kt
index 8b818cff1b..9d8e0aa9c4 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseError.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseError.kt
@@ -18,6 +18,54 @@ sealed class ApiResponseError : Exception() {
val errorBody: String?,
) : ApiResponseError() {
+ fun isServerError(): Boolean = when (code) {
+ Code.OK,
+ Code.CREATED,
+ Code.ACCEPTED,
+ Code.NOT_MODIFIED,
+ Code.BAD_REQUEST,
+ Code.UNAUTHORIZED,
+ Code.PAYMENT_REQUIRED,
+ Code.FORBIDDEN,
+ Code.NOT_FOUND,
+ Code.METHOD_NOT_ALLOWED,
+ Code.NOT_ACCEPTABLE,
+ Code.PROXY_AUTHENTICATION_REQUIRED,
+ Code.REQUEST_TIMEOUT,
+ Code.CONFLICT,
+ Code.GONE,
+ Code.LENGTH_REQUIRED,
+ Code.PRECONDITION_FAILED,
+ Code.PAYLOAD_TOO_LARGE,
+ Code.URI_TOO_LONG,
+ Code.UNSUPPORTED_MEDIA_TYPE,
+ Code.RANGE_NOT_SATISFIABLE,
+ Code.EXPECTATION_FAILED,
+ Code.IM_A_TEAPOT,
+ Code.UNPROCESSABLE_ENTITY,
+ Code.LOCKED,
+ Code.FAILED_DEPENDENCY,
+ Code.TOO_EARLY,
+ Code.UPGRADE_REQUIRED,
+ Code.PRECONDITION_REQUIRED,
+ Code.TOO_MANY_REQUESTS,
+ Code.REQUEST_HEADER_FIELDS_TOO_LARGE,
+ Code.UNAVAILABLE_FOR_LEGAL_REASONS,
+ -> false
+ Code.INTERNAL_SERVER_ERROR,
+ Code.NOT_IMPLEMENTED,
+ Code.BAD_GATEWAY,
+ Code.SERVICE_UNAVAILABLE,
+ Code.GATEWAY_TIMEOUT,
+ Code.HTTP_VERSION_NOT_SUPPORTED,
+ Code.VARIANT_ALSO_NEGOTIATES,
+ Code.INSUFFICIENT_STORAGE,
+ Code.LOOP_DETECTED,
+ Code.NOT_EXTENDED,
+ Code.NETWORK_AUTHENTICATION_REQUIRED,
+ -> true
+ }
+
// TODO: extract Code from HttpException
// region Error Codes
enum class Code(val numericCode: Int) {
diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml
index faddf299c6..dea8c07645 100644
--- a/core/res/src/main/res/values-fr/strings.xml
+++ b/core/res/src/main/res/values-fr/strings.xml
@@ -896,6 +896,8 @@
La réinitialisation aux paramètres d\'usine supprimera complètement le portefeuille de la carte sélectionnée et le supprimera de l\'application. Vous ne pourrez pas restaurer le portefeuille actuel.
Les propriétaires du Tangem Ring ont droit à 3 swap gratis sur Changelly jusqu\'au 15/11 !
Échangez avec 0 % de frais !
+ Les appareils disposant d\'un accès root sont considérés comme moins sécurisés. Vos données peuvent être exposées à des risques supplémentaires.
+ Accès root détecté
Connectez-vous à l\'application et vérifiez votre solde sans scanner la carte
Accéder à l\'application
Autoriser l\'utilisation de la biométrie
diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml
index bce005b585..70f1b95349 100644
--- a/core/res/src/main/res/values-ja/strings.xml
+++ b/core/res/src/main/res/values-ja/strings.xml
@@ -103,10 +103,10 @@
設定に移動して、Tangemアプリで生体認証を有効にします。
生体認証を有効にする
%1$sが無効になると、アプリのロックを解除してウォレットを操作するために、パスコードを入力する必要があります。
- 後でウォレットのアクセスコードを入力してもらいます。それを安全に保存し、今後の利用に備えるためです。
- これにより、保存されているウォレットアクセスコードがすべて削除されます。ウォレットでの今後の操作には、アクセスコードの送信が必要になります。
+ 安全に保管するため、後ほどアクセスコードの入力を求められます。
+ 保存されているすべてのウォレットのアクセスコードが削除されます。ウォレットを使用するには、再度アクセスコードを入力する必要があります。
保存したデバイスを削除すると、保存されているすべてのウォレットとそのアクセスコードがアプリから削除されます。
- これにより、保存されているウォレットアクセスコードがすべて削除されます。今後ウォレットを操作するには、アクセスコードの送信が必要になります。
+ 保存されているすべてのウォレットのアクセスコードが削除されます。ウォレットを使用するには、再度アクセスコードを入力する必要があります。
アクセスコードを要求する
このオプションを選択すると、機密性の高い操作における生体認証が無効になります。取引に署名するたびにアクセスコードを入力する必要があります。
アクセスコードを保存
@@ -144,10 +144,10 @@
残高は非表示
ブロックチェーン開発者によると、Kaspaトークンは現在ベータ版です。アップデートをお楽しみに!
ベータモード
- デバイスで生体認証がオフになっているため、ウォレットのロック解除に使用できません。生体認証を再度利用するには、デバイスの設定で有効にしてください。
+ この端末では生体認証がオフになっているため、ウォレットの解除に使用できません。再度この方法を使用するには、端末の設定で生体認証を有効にしてください。
生体認証が無効になっています
カードまたはリングをスキャンしてください
- 生体認証の試行回数が上限に達しました。端末タップまたはアクセスコードでウォレットを解除してください。
+ 生体認証の試行回数の上限に達しました。カード/リングでウォレットを解除するか、アクセスコードを入力してください。
生体認証がロックされています
30秒後に再試行するか、カードまたはリングをスキャンしてください
生体認証ログインは一時的にロックされています。30秒後にもう一度お試しいただくか、端末タップまたはアクセスコードでウォレットを解除してください。
@@ -179,7 +179,7 @@
もう一度アップグレードしてください
リセット完了
このウォレット内のすべてのTangemデバイスで、リセット処理を完了することを推奨します。
- すべてのTangemデバイスをリセットしていません
+ リセットが必要なTangemデバイスがあります。
このカードを使用して、このウォレット内の他のカードまたはリングのアクセスコードをリセットしたくない場合は、このオプションを無効にしてください。これにより、このカードのアクセスコードもリセットできなくなりますのでご注意ください。
このカードを使用して、このウォレット内の他のカードのアクセスコードをリセットできます。
アクセスコードの復元
@@ -378,6 +378,7 @@
送金
データを読み込めません…
わかりました
+ 理解して続行
エラーが発生しました。もう一度お試しください。
アクセスできません
ステーキング解除
@@ -567,7 +568,7 @@
新しいウォレットを作成する
Tangemを注文
Tangemをスキャン
- 「Tangem」に生体認証の使用を許可しますか?\n本人確認とアプリの起動のために使用されます。
+ 「Tangem」が生体認証を使用して本人確認を行い、アプリを開くことを許可しますか?
%sへ
%sネットワーク
アクセスコードの設定をキャンセルしてもよろしいですか?
@@ -1059,6 +1060,7 @@
カードをリセットする
この操作を実行すると、現在のウォレットにアクセスできなくなることを理解しています。
このカードを使用して、現在のウォレットの他のカードのアクセスコードを回復させられないことを認識しています。
+ 復元は不可能であり、Tangem Payカードおよびカード上のすべての資金へのアクセスを完全に失うことを理解しました
工場出荷時設定にリセットすると、選択したカードやリングからウォレットが完全に削除されます。現在のウォレットを復元したり、カードやリングを使用してアクセスコードを復元することはできません。
工場出荷時の状態にリセットすると、選択したカードやリングからウォレットが完全に削除され、アプリから削除されます。現在のウォレットを復元することはできません。
すべてのTangemデバイスがリセットされました。
@@ -1067,6 +1069,8 @@
続行するには次のデバイスをリセットしてください
Tangem Ringユーザーは、11/15日までChangelly経由でスワップを3回手数料ゼロで行えます!
今すぐ手数料0% でスワップしましょう!
+ Rootアクセスが有効な端末は、セキュリティが低いと判断されます。データが追加のリスクにさらされる可能性があります。
+ Rootアクセスが検出されました
アプリにログインして、カードまたはリングをスキャンせずに残高を確認できます
アプリにアクセスする
生体認証の使用を許可する
@@ -1402,6 +1406,7 @@
カードが凍結されています
サポートを受ける
その他
+ Root化された端末では使用できません
完了
拒否
保留中
@@ -1414,6 +1419,8 @@
カードの凍結解除に失敗しました。しばらくしてからもう一度お試しください。
カードの凍結が解除されました
出金
+ Root化された端末では使用できません
+ KYCをキャンセル
資金を追加
入金オプション
カード番号
@@ -1441,6 +1448,7 @@
準備完了!カードはすぐに使用できます。
Google Payにカードを追加する
Apple Payにカードを追加する
+ PINコード
アドレスを共有するか、QRコードを表示してください。
技術的な問題が検出されました。しばらくしてからもう一度お試しいただくか、サポートにお問い合わせください。
現在、受け取りは利用できません
@@ -1449,12 +1457,15 @@
ポートフォリオ内のあらゆる資産をカードと交換
カードの詳細
カードの一時停止を解除
+ 忘れた場合は、アプリに戻ってください。
+ PINコード
出金
現在、出金ができません
現在の処理が完了するまでは、スワップや新しい出金を開始することはできません。
出金処理中です
PINコードを変更
忘れた場合はアプリに戻って確認できます。
+ 復元は不可能であり、Tangem Payカードおよびカード上のすべての資金へのアクセスを完全に失うことを理解しました
カードの発行に失敗しました
技術的なエラーが発生しました。下のボタンをクリックして、もう一度お試しください。
技術的なエラーが発生しました。サポートへお問い合わせください。
@@ -1471,6 +1482,7 @@
KYC進行中
ステータスを表示
Tangem PayのKYC手続き進行中
+ 以下のボタンから、現在のKYCステータスを確認するか、KYCをキャンセルできます。
暗号資産を、リアルな支払いに。\n他とはまったく違う、新しいタイプの決済カード。
Tangem Visaカード
カードをGET
@@ -1488,7 +1500,7 @@
現在、データを表示できませんが、カードでのお支払いは引き続きご利用いただけます。
同期が必要です
Tangem Visaカード
- Tangem Payは一時的に利用できません
+ Tangem Payは現在一時的に利用できません。
Tangem Pay
カードまたはリングを使用して、支払いアカウントへのアクセスを復元してください。
PINコード
@@ -1572,7 +1584,7 @@
プッシュ通知を使用しますか?
プッシュ通知を有効にすると、ウォレットに着金したときにアラートを受信できます。
取引を見逃さない
- 新しいウォレットを追加
+ ウォレットを追加
バックアップせずにこのウォレットを削除すると、資金に永久にアクセスできなくなります。
このウォレットを忘れてもよろしいですか?
エラーが発生しました。カードまたはリングをスキャンしてログインしてください。
@@ -1879,7 +1891,7 @@
不審な取引
すでにTangemウォレットをお持ちですか?
数千種類の資産
- 業界最高水準のハードウェアウォレット
+ 最高水準のハードウェアウォレット
迅速な配送
ワンタップで開始
シームレスで安全
diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 03ce372d0f..036b504b45 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -394,6 +394,7 @@
Перевод
Невозможно загрузить данные…
Я понял
+ Я понимаю, продолжить
Произошла ошибка. Пожалуйста, попробуйте снова.
Недоступно
Завершить стейкинг
@@ -733,6 +734,7 @@
Лидеры роста
Лидеры падения
В тренде
+ Режим доходности
Стейкинг — простой способ получать доход с вашей криптовалюты. %s
Получайте до %s APY
Токен добавлен
@@ -994,6 +996,7 @@
Другие валюты
Популярные фиаты
Поиск по валюте
+ Эта транзакция уже была обработана. Дополнительных действий не требуется.
Получение лучших курсов...
Моментально
Пользуясь сервисом покупки, вы соглашаетесь с %1$s и %2$s
@@ -1104,6 +1107,8 @@
Сбросьте следующее устройство для продолжения.
Владельцам колец — 3 обмена без комиссии на Changelly до 15.11!
Обмен с 0% комиссией!
+ Устройства с root-доступом считаются менее безопасными. Ваши данные могут быть подвержены дополнительным рискам.
+ Обнаружен root-доступ
Войдите в приложение и следите за своим балансом без сканирования карты или кольца
Доступ в приложение
Использовать биометрию
@@ -1493,6 +1498,7 @@
Вывод выполняется
Изменить PIN-код
Можно посмотреть здесь, если забудете его.
+ Я понимаю, что полностью потеряю доступ к своей карте Tangem Pay и ко всем средствам на ней без возможности восстановления.
Не удалось выпустить карту
Техническая ошибка, попробуйте ещё раз, нажав кнопку ниже
Техническая ошибка, свяжитесь с поддержкой
@@ -1964,6 +1970,7 @@
Политика комиссий за пополнение
Tangem взимает комиссию за обслуживание в размере 15% от полученного дохода.
Ваши средства будут автоматически переведены в Aave, как только комиссия сети снизится или баланс достигнет минимально необходимой суммы.
+ Комиссии сейчас выше обычного из-за высокой активности на рынке. Вы можете продолжить сейчас или вернуться позже, когда комиссии снизятся.
Высокая сетевая комиссия
Историческая доходность
Получай до %1$s APY на свой баланс
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 7e87d0d441..eaddf5b46e 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -1444,6 +1444,7 @@
Your card is unfrozen.
Withdrawal
Unable to use on rooted device
+ Cancel KYC
Add funds
Top-up options
Card Number
@@ -1505,6 +1506,7 @@
KYC in progress
View Status
KYC in progress for Tangem Pay
+ Use the buttons below to view your current KYC status or cancel it.
Use your crypto for real world spending. \nIt’s a payment card unlike any other.
Tangem Visa Card
Get card
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/YieldSupplyPromoBanner.kt b/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/YieldSupplyPromoBanner.kt
index 31ddd112b2..b949061451 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/YieldSupplyPromoBanner.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/YieldSupplyPromoBanner.kt
@@ -44,8 +44,8 @@ internal fun YieldSupplyPromoBanner(state: PromoBannerState.Content, modifier: M
Row(
modifier = Modifier
.background(color = bgColor, shape = TangemTheme.shapes.roundedCornersXMedium)
- .padding(horizontal = 12.dp, vertical = 8.dp)
.clickable(onClick = state.onPromoBannerClick)
+ .padding(horizontal = 12.dp, vertical = 8.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
) {
diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt
index 83e30d675e..95b6decdf8 100644
--- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt
+++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt
@@ -172,10 +172,11 @@ internal class TangemPayRequestPerformer @Inject constructor(
refreshToken = response.refreshToken,
refreshExpiresAt = response.refreshExpiresAt,
)
+ }.mapLeft { error ->
+ Timber.tag(TAG).e("Can not refresh auth tokens: $error")
+ if (error is VisaApiError.ServerUnavailable) error else VisaApiError.RefreshTokenExpired
}.onRight { tokens ->
tangemPayStorage.storeAuthTokens(customerWalletAddress = customerWalletAddress, tokens = tokens)
- }.onLeft {
- Timber.tag(TAG).e("Can not refresh auth tokens: $it")
}
}
}
\ No newline at end of file
diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/util/TangemPayErrorConverter.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/util/TangemPayErrorConverter.kt
index 1b81ab80eb..23ee03289a 100644
--- a/data/visa/src/main/kotlin/com/tangem/data/pay/util/TangemPayErrorConverter.kt
+++ b/data/visa/src/main/kotlin/com/tangem/data/pay/util/TangemPayErrorConverter.kt
@@ -18,6 +18,7 @@ internal class TangemPayErrorConverter @Inject constructor(
override fun convert(value: Throwable): VisaApiError {
return if (value is ApiResponseError.HttpException) {
+ if (value.isServerError()) return VisaApiError.ServerUnavailable
if (value.code == ApiResponseError.HttpException.Code.NOT_FOUND) return VisaApiError.NotPaeraCustomer
if (value.code == ApiResponseError.HttpException.Code.UNAUTHORIZED) return VisaApiError.RefreshTokenExpired
diff --git a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/DefaultWalletManagersFacade.kt b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/DefaultWalletManagersFacade.kt
index 7e669ccebb..842ce80393 100644
--- a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/DefaultWalletManagersFacade.kt
+++ b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/DefaultWalletManagersFacade.kt
@@ -281,8 +281,10 @@ internal class DefaultWalletManagersFacade @Inject constructor(
is Result.Success -> PaginationWrapper(
currentPage = sdkPageConverter.convert(page),
nextPage = sdkPageConverter.convert(itemsResult.data.nextPage),
- items = SdkTransactionHistoryItemConverter(smartContractMethods = readSmartContractMethods())
- .convertList(itemsResult.data.items),
+ items = SdkTransactionHistoryItemConverter(
+ smartContractMethods = readSmartContractMethods(),
+ yieldSupplyAddresses = YIELD_SUPPLY_ADDRESSES,
+ ).convertList(itemsResult.data.items),
)
is Result.Failure -> error(itemsResult.error.message ?: itemsResult.error.customMessage)
}
diff --git a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionHistoryItemConverter.kt b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionHistoryItemConverter.kt
index 1a677b9cdb..51d7e2fd6e 100644
--- a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionHistoryItemConverter.kt
+++ b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionHistoryItemConverter.kt
@@ -8,9 +8,13 @@ import com.tangem.blockchain.transactionhistory.models.TransactionHistoryItem as
internal class SdkTransactionHistoryItemConverter(
smartContractMethods: Map,
+ yieldSupplyAddresses: Set,
) : Converter {
- private val typeConverter by lazy { SdkTransactionTypeConverter(smartContractMethods) }
+ private val typeConverter by lazy { SdkTransactionTypeConverter(
+ smartContractMethods = smartContractMethods,
+ yieldSupplyAddresses = yieldSupplyAddresses,
+ ) }
override fun convert(value: SdkTransactionHistoryItem): TxInfo = TxInfo(
txHash = value.txHash,
@@ -24,7 +28,7 @@ internal class SdkTransactionHistoryItemConverter(
SdkTransactionHistoryItem.TransactionStatus.Failed -> TxInfo.TransactionStatus.Failed
SdkTransactionHistoryItem.TransactionStatus.Unconfirmed -> TxInfo.TransactionStatus.Unconfirmed
},
- type = typeConverter.convert(value.type to value.destinationType.toDomain()),
+ type = typeConverter.convert(value),
amount = requireNotNull(value.amount.value) { "Transaction amount value must not be null" },
)
diff --git a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionTypeConverter.kt b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionTypeConverter.kt
index 5e9fe1dc0b..639350d503 100644
--- a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionTypeConverter.kt
+++ b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionTypeConverter.kt
@@ -1,5 +1,6 @@
package com.tangem.data.walletmanager.utils
+import com.tangem.blockchain.transactionhistory.models.TransactionHistoryItem
import com.tangem.blockchain.transactionhistory.models.TransactionHistoryItem.TransactionType
import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyEnterCallData
import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyExitCallData
@@ -11,17 +12,29 @@ import com.tangem.utils.converter.Converter
internal class SdkTransactionTypeConverter(
private val smartContractMethods: Map,
-) : Converter, TxInfo.TransactionType> {
+ private val yieldSupplyAddresses: Set,
+) : Converter {
- override fun convert(value: Pair): TxInfo.TransactionType {
- val (type, destination) = value
+ override fun convert(value: TransactionHistoryItem): TxInfo.TransactionType {
+ val (type, destination) = value.type to value.destinationType
+ val source = value.sourceType
return when (type) {
is TransactionType.ContractMethod -> {
- getTransactionType(methodName = smartContractMethods[type.id]?.name, type.callData, destination)
+ getTransactionType(
+ methodName = smartContractMethods[type.id]?.name,
+ callData = type.callData,
+ destination = destination,
+ source = source,
+ )
}
is TransactionType.ContractMethodName -> {
- getTransactionType(methodName = type.name, type.callData, destination)
+ getTransactionType(
+ methodName = type.name,
+ callData = type.callData,
+ destination = destination,
+ source = source,
+ )
}
is TransactionType.Transfer -> {
TxInfo.TransactionType.Transfer
@@ -48,7 +61,8 @@ internal class SdkTransactionTypeConverter(
private fun getTransactionType(
methodName: String?,
callData: String?,
- destination: TxInfo.DestinationType,
+ destination: TransactionHistoryItem.DestinationType,
+ source: TransactionHistoryItem.SourceType,
): TxInfo.TransactionType {
return when (methodName) {
"transfer" -> TxInfo.TransactionType.Transfer
@@ -70,7 +84,21 @@ internal class SdkTransactionTypeConverter(
"withdrawRewardsPOL",
-> TxInfo.TransactionType.Staking.ClaimRewards
"redelegate" -> TxInfo.TransactionType.Staking.Restake
- "yieldSend" -> TxInfo.TransactionType.YieldSupply.Send
+ "yieldSend" -> {
+ val sourceAddresses = when (source) {
+ is TransactionHistoryItem.SourceType.Multiple -> source.addresses
+ is TransactionHistoryItem.SourceType.Single -> listOf(source.address)
+ }.map {
+ it.lowercase()
+ }.toSet()
+
+ val isYieldSupplyWithdraw =
+ yieldSupplyAddresses.intersect(sourceAddresses).isNotEmpty()
+
+ TxInfo.TransactionType.YieldSupply.Send(
+ isYieldSupplyWithdraw = isYieldSupplyWithdraw,
+ )
+ }
"enterProtocolByOwner" -> callData?.let { data ->
TxInfo.TransactionType.YieldSupply.Enter(
EthereumYieldSupplyEnterCallData.decode(data)?.tokenContractAddress.orEmpty(),
@@ -82,7 +110,7 @@ internal class SdkTransactionTypeConverter(
)
}
"deployYieldModule" -> TxInfo.TransactionType.YieldSupply.DeployContract(
- (destination as? TxInfo.DestinationType.Single)?.addressType?.address.orEmpty(),
+ (destination as? TransactionHistoryItem.DestinationType.Single)?.addressType?.address.orEmpty(),
)
"initYieldToken" -> callData?.let { data ->
TxInfo.TransactionType.YieldSupply.InitializeToken(
diff --git a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/YieldSupplyAddresses.kt b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/YieldSupplyAddresses.kt
new file mode 100644
index 0000000000..22e28e3eb6
--- /dev/null
+++ b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/YieldSupplyAddresses.kt
@@ -0,0 +1,113 @@
+package com.tangem.data.walletmanager.utils
+
+// Remove after moving this data to BE
+internal val YIELD_SUPPLY_ADDRESSES: Set = setOf(
+ "0x00901a076785e0906d1028c7d6372d247bec7d61",
+ "0x00907f9921424583e7ffbfedf84f92b7b2be4977",
+ "0x018008bfb33d285247a21d44e50697654f754e63",
+ "0x067ae75628177fd257c2b1e500993e1a0babcbd1",
+ "0x078f358208685046a11c85e8ad32895ded33a249",
+ "0x0a1d576f3efef75b330424287a95a366e8281d54",
+ "0x0b925ed163218f6662a35e0f0371ac234f9e9371",
+ "0x0c0d01abf3e6adfca0989ebba9d6e85dd58eab1e",
+ "0x10ac93971cdb1f5c778144084242374473c350da",
+ "0x191c10aa4af7c30e871e70c95db0e4eb77237530",
+ "0x1ba9843bd4327c6c77011406de5fa8749f7e3479",
+ "0x1c0e06a0b1a4c160c17545ff2a951bfca57c0002",
+ "0x23878914efe38d27c4d67ab83ed1b93a74d4086a",
+ "0x24ab03a9a5bc2c49e5523e8d915a3536ac38b91d",
+ "0x2516e7b3f76294e03c42aa4c5b5b4dce9c436fb8",
+ "0x285866acb0d60105b4ed350a463361c2d9afa0e2",
+ "0x2d62109243b87c4ba3ee7ba1d91b0dd0a074d7b1",
+ "0x2e94171493fabe316b6205f1585779c887771e2f",
+ "0x2edff5af94334fbd7c38ae318edf1c40e072b73b",
+ "0x312ffc57778cefa11989733e6e08143e7e229c1c",
+ "0x32a6268f9ba3642dda7892add74f1d34469a4259",
+ "0x38a5357ce55c81add62abc84fb32981e2626adef",
+ "0x38c503a438185cde29b5cf4dc1442fd6f074f1cc",
+ "0x38d693ce1df5aadf7bc62595a37d667ad57922e5",
+ "0x3fe6a295459fae07df8a0cecc36f37160fe86aa9",
+ "0x40b4baecc69b882e8804f9286b12228c27f8c9bf",
+ "0x4199cc1f5ed0d796563d7ccb2e036253e2c18281",
+ "0x44705f578135cc5d703b4c9c122528c73eb87145",
+ "0x4579a27af00a62c0eb156349f31b345c08386419",
+ "0x481a2acf3a72ffdc602a9541896ca1db87f86cf7",
+ "0x4b0821e768ed9039a70ed1e80e15e76a5be5df5f",
+ "0x4c612e3b15b96ff9a6faed838f8d07d479a8dd4c",
+ "0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8",
+ "0x4e2a4d9b3df7aae73b418bd39f3af9e148e3f479",
+ "0x4e65fe4dba92790696d040ac24aa414708f5c0ab",
+ "0x4f5923fc5fd4a93352581b38b7cd26943012decf",
+ "0x513c7e3a9c69ca3e22550ef58ac1c0088e918fff",
+ "0x545bd6c032efdde65a377a6719def2796c8e0f2e",
+ "0x56a7ddc4e848ebf43845854205ad71d5d5f72d3d",
+ "0x5b502e3796385e1e9755d7043b9c945c3accec9c",
+ "0x5c647ce0ae10658ec44fa4e11a51c96e94efd1dd",
+ "0x5e8c8a7243651db1384c0ddfdbe39761e8e7e51a",
+ "0x5ee5bf7ae06d1be5997a1a72006fe6c607ec6de8",
+ "0x5f4a0873a3a02f7c0cb0e13a1d4362a1ad90e751",
+ "0x5f9190496e0dfc831c3bd307978de4a245e2f5cd",
+ "0x5fefd7069a7d91d01f269dade14526ccf3487810",
+ "0x625e7708f30ca75bfd92586e17077590c60eb4cd",
+ "0x62fc96b27a510cf4977b59ff952dc32378cc221d",
+ "0x6533afac2e7bccb20dca161449a13a32d391fb00",
+ "0x65906988adee75306021c417a1a3458040239602",
+ "0x67eaf2bee4384a2f84da9eb8105c661c123736ba",
+ "0x6ab707aca953edaefbc4fd23ba73294241490620",
+ "0x6b030ff3fb9956b1b69f475b77ae0d3cf2cc5afa",
+ "0x6d80113e533a2c0fe82eabd35f1875dcea89ea97",
+ "0x71aef7b30728b9bb371578f36c5a1f1502a5723e",
+ "0x724dc807b04555b71ed48a6896b6f41593b8c637",
+ "0x75bd1a659bdc62e4c313950d44a2416fab43e785",
+ "0x7b95ec873268a6bfc6427e7a28e396db9d0ebc65",
+ "0x7c307e128efa31f540f2e2d976c995e0b65f51f6",
+ "0x80a94c36747cf51b2fbabdff045f6d22c1930ed1",
+ "0x80ca0d8c38d2e2bcbab66aa1648bd1c7160500fe",
+ "0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee",
+ "0x82f9c5ad306bba1ad0de49bb5fa6f01bf61085ef",
+ "0x8437d7c167dfb82ed4cb79cd44b7a32a1dd95c77",
+ "0x8a2b6f94ff3a89a03e8c02ee92b55af90c9454a2",
+ "0x8a458a9dc9048e005d22849f470891b840296619",
+ "0x8a9fde6925a839f6b1932d16b36ac026f8d3fbdb",
+ "0x8eb270e296023e9d92081fdf967ddd7878724424",
+ "0x8ffdf2de812095b1d19cb146e4c004587c0a0692",
+ "0x90072a4aa69b5eb74984ab823efc5f91e90b3a72",
+ "0x90da57e0a6c0d166bf15764e03b83745dc90025b",
+ "0x927709711794f3de5ddbf1d176bee2d55ba13c21",
+ "0x977b6fc5de62598b08c85ac8cf2b745874e8b78c",
+ "0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c",
+ "0x99cbc45ea5bb7ef3a5bc08fb1b7e56bb2442ef0d",
+ "0x9a44fd41566876a39655f74971a3a6ea0a17a454",
+ "0x9b00a09492a626678e5a3009982191586c444df9",
+ "0xa4d94019934d8333ef880abffbf2fdd611c762bd",
+ "0xa700b4eb416be35b2911fd5dee80678ff64ff6c9",
+ "0xa9251ca9de909cb71783723713b21e4233fbf1b1",
+ "0xaa0200d169ff3ba9385c12e073c5d1d30434ae7b",
+ "0xaa6e91c82942aeae040303bf96c15a6dbcb82ca0",
+ "0xb76cf92076adbf1d9c39294fa8e7a67579fde357",
+ "0xb82fa9f31612989525992fcfbb09ab22eff5c85a",
+ "0xbcffb4b3beadc989bd1458740952af6ec8fbe431",
+ "0xbdb9300b7cde636d9cd4aff00f6f009ffbbc8ee6",
+ "0xbdfa7b7893081b35fb54027489e2bc7a38275129",
+ "0xbdfd4e51d3c14a232135f04988a42576efb31519",
+ "0xbe54767735fb7acca2aa7e2d209a6f705073536d",
+ "0xc45a479877e1e9dfe9fcd4056c699575a1045daa",
+ "0xc7b4c17861357b8abb91f25581e7263e08dcb59c",
+ "0xcc9ee9483f662091a1de4795249e24ac0ac2630f",
+ "0xcca43cef272c30415866914351fdfc3e881bb7c2",
+ "0xcf3d55c10db69f28fd1a75bd73f3d8a2d9c595ad",
+ "0xd4a0e0b9149bcee3c920d2e00b5de09138fd8bb7",
+ "0xd4e245848d6e1220dbe62e155d89fa327e43cb06",
+ "0xdd5745756c2de109183c6b5bb886f9207bef114d",
+ "0xde6ef6cb4abd3a473ffc2942eef5d84536f8e864",
+ "0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8",
+ "0xe728577e9a1fe7032bc309b4541f58f45443866e",
+ "0xea1132120ddcdda2f119e99fa7a27a0d036f7ac9",
+ "0xebe517846d0f36eced99c735cbf6131e1feb775d",
+ "0xec4ef66d4fceeba34abb4de69db391bc5476ccc8",
+ "0xf329e36c7bf6e5e86ce2150875a84ce77f477375",
+ "0xf59036caebea7dc4b86638dfa2e3c97da9fccd40",
+ "0xf611aeb5013fd2c0511c9cd55c7dc5c1140741a6",
+ "0xf6d2224916ddfbbab6e6bd0d1b7034f4ae0cab18",
+ "0xfa82580c16a31d0c1bc632a36f82e83efef3eec0",
+)
\ No newline at end of file
diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/currency/CryptoCurrencyExtensions.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/currency/CryptoCurrencyExtensions.kt
index 09c43362de..cc408905ee 100644
--- a/domain/models/src/main/kotlin/com/tangem/domain/models/currency/CryptoCurrencyExtensions.kt
+++ b/domain/models/src/main/kotlin/com/tangem/domain/models/currency/CryptoCurrencyExtensions.kt
@@ -7,16 +7,16 @@ fun CryptoCurrency.Token.yieldSupplyKey(): String {
}
fun CryptoCurrencyStatus.hasNotSuppliedAmount(): Boolean {
- val notSupplied = notSuppliedAmountOrNull() ?: return false
+ val notSupplied = notSuppliedCryptoAmountOrNull() ?: return false
return notSupplied > BigDecimal.ZERO
}
-fun CryptoCurrencyStatus.shouldShowNotSuppliedInfoIcon(dustAmount: BigDecimal): Boolean {
- val notSupplied = notSuppliedAmountOrNull() ?: return false
+fun CryptoCurrencyStatus.shouldShowNotSuppliedNotification(dustAmount: BigDecimal): Boolean {
+ val notSupplied = notSuppliedCryptoAmountOrNull()?.multiply(this.value.fiatRate) ?: return false
return notSupplied >= dustAmount
}
-fun CryptoCurrencyStatus.notSuppliedAmountOrNull(): BigDecimal? {
+fun CryptoCurrencyStatus.notSuppliedCryptoAmountOrNull(): BigDecimal? {
if (this.currency !is CryptoCurrency.Token) return null
val supplyStatus = this.value.yieldSupplyStatus
diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt
index d8fd074625..aae35a95f1 100644
--- a/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt
+++ b/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt
@@ -124,9 +124,10 @@ data class TxInfo(
}
@Serializable
- data object Send : YieldSupply {
- override val address: String? = null
- }
+ data class Send(
+ override val address: String? = null,
+ val isYieldSupplyWithdraw: Boolean,
+ ) : YieldSupply
@Serializable
data class DeployContract(override val address: String) : YieldSupply
diff --git a/domain/models/src/test/kotlin/com/tangem/domain/models/currency/CryptoCurrencyExtensionsTest.kt b/domain/models/src/test/kotlin/com/tangem/domain/models/currency/CryptoCurrencyExtensionsTest.kt
new file mode 100644
index 0000000000..402352cc42
--- /dev/null
+++ b/domain/models/src/test/kotlin/com/tangem/domain/models/currency/CryptoCurrencyExtensionsTest.kt
@@ -0,0 +1,417 @@
+package com.tangem.domain.models.currency
+
+import com.google.common.truth.Truth.assertThat
+import com.tangem.domain.models.yield.supply.YieldSupplyStatus
+import io.mockk.every
+import io.mockk.mockk
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.TestInstance
+import java.math.BigDecimal
+
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+class CryptoCurrencyExtensionsTest {
+
+ @Test
+ fun `GIVEN currency is Coin WHEN hasNotSuppliedAmount THEN returns false`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ )
+
+ val result = status.hasNotSuppliedAmount()
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN yieldSupplyStatus is null WHEN hasNotSuppliedAmount THEN returns false`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = null,
+ )
+
+ val result = status.hasNotSuppliedAmount()
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN yieldSupplyStatus isActive is false WHEN hasNotSuppliedAmount THEN returns false`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = false,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = BigDecimal.TEN,
+ ),
+ )
+
+ val result = status.hasNotSuppliedAmount()
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN effectiveProtocolBalance is null WHEN hasNotSuppliedAmount THEN returns false`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = null,
+ ),
+ amount = BigDecimal.TEN,
+ )
+
+ val result = status.hasNotSuppliedAmount()
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN amount is null WHEN hasNotSuppliedAmount THEN returns false`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = BigDecimal.TEN,
+ ),
+ amount = null,
+ )
+
+ val result = status.hasNotSuppliedAmount()
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN notSupplied is zero WHEN hasNotSuppliedAmount THEN returns false`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = BigDecimal.TEN,
+ ),
+ amount = BigDecimal.TEN,
+ )
+
+ val result = status.hasNotSuppliedAmount()
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN notSupplied is negative WHEN hasNotSuppliedAmount THEN returns false`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = BigDecimal.TEN,
+ ),
+ amount = BigDecimal.ONE,
+ )
+
+ val result = status.hasNotSuppliedAmount()
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN notSupplied is positive WHEN hasNotSuppliedAmount THEN returns true`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = BigDecimal.ONE,
+ ),
+ amount = BigDecimal.TEN,
+ )
+
+ val result = status.hasNotSuppliedAmount()
+
+ assertThat(result).isTrue()
+ }
+
+ @Test
+ fun `GIVEN currency is Coin WHEN shouldShowNotSuppliedNotification THEN returns false`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ )
+
+ val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.ONE)
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN yieldSupplyStatus is null WHEN shouldShowNotSuppliedNotification THEN returns false`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = null,
+ )
+
+ val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.ONE)
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN yieldSupplyStatus isActive is false WHEN shouldShowNotSuppliedNotification THEN returns false`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = false,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = BigDecimal.TEN,
+ ),
+ )
+
+ val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.ONE)
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN effectiveProtocolBalance is null WHEN shouldShowNotSuppliedNotification THEN returns false`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = null,
+ ),
+ amount = BigDecimal.TEN,
+ fiatRate = BigDecimal.ONE,
+ )
+
+ val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.ONE)
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN notSupplied in fiat is less than dustAmount WHEN shouldShowNotSuppliedNotification THEN returns false`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = BigDecimal("9"),
+ ),
+ amount = BigDecimal.TEN,
+ fiatRate = BigDecimal.ONE,
+ )
+
+ val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.TEN)
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN notSupplied in fiat equals dustAmount WHEN shouldShowNotSuppliedNotification THEN returns true`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = BigDecimal("5"),
+ ),
+ amount = BigDecimal.TEN,
+ fiatRate = BigDecimal("2"),
+ )
+
+ val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.TEN)
+
+ assertThat(result).isTrue()
+ }
+
+ @Test
+ fun `GIVEN notSupplied in fiat is greater than dustAmount WHEN shouldShowNotSuppliedNotification THEN returns true`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = BigDecimal.ONE,
+ ),
+ amount = BigDecimal.TEN,
+ fiatRate = BigDecimal("2"),
+ )
+
+ val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.TEN)
+
+ assertThat(result).isTrue()
+ }
+
+ @Test
+ fun `GIVEN USDT with EUR fiat rate and notSupplied below dust WHEN shouldShowNotSuppliedNotification THEN returns false`() {
+ val usdtToEurRate = BigDecimal("0.93")
+ val notSuppliedUsdt = BigDecimal("0.05")
+ val protocolBalance = BigDecimal("100")
+ val totalAmount = protocolBalance.add(notSuppliedUsdt)
+ val dustAmountEur = BigDecimal("0.1")
+
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = protocolBalance,
+ ),
+ amount = totalAmount,
+ fiatRate = usdtToEurRate,
+ )
+
+ val result = status.shouldShowNotSuppliedNotification(dustAmount = dustAmountEur)
+
+ assertThat(result).isFalse()
+ }
+
+ @Test
+ fun `GIVEN USDT with EUR fiat rate and notSupplied above dust WHEN shouldShowNotSuppliedNotification THEN returns true`() {
+ val usdtToEurRate = BigDecimal("0.93")
+ val notSuppliedUsdt = BigDecimal("0.15")
+ val protocolBalance = BigDecimal("100")
+ val totalAmount = protocolBalance.add(notSuppliedUsdt)
+ val dustAmountEur = BigDecimal("0.1")
+
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = protocolBalance,
+ ),
+ amount = totalAmount,
+ fiatRate = usdtToEurRate,
+ )
+
+ val result = status.shouldShowNotSuppliedNotification(dustAmount = dustAmountEur)
+
+ assertThat(result).isTrue()
+ }
+
+ @Test
+ fun `GIVEN currency is Coin WHEN notSuppliedCryptoAmountOrNull THEN returns null`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ )
+
+ val result = status.notSuppliedCryptoAmountOrNull()
+
+ assertThat(result).isNull()
+ }
+
+ @Test
+ fun `GIVEN yieldSupplyStatus is null WHEN notSuppliedCryptoAmountOrNull THEN returns null`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = null,
+ )
+
+ val result = status.notSuppliedCryptoAmountOrNull()
+
+ assertThat(result).isNull()
+ }
+
+ @Test
+ fun `GIVEN yieldSupplyStatus isActive is false WHEN notSuppliedCryptoAmountOrNull THEN returns null`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = false,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = BigDecimal.TEN,
+ ),
+ )
+
+ val result = status.notSuppliedCryptoAmountOrNull()
+
+ assertThat(result).isNull()
+ }
+
+ @Test
+ fun `GIVEN effectiveProtocolBalance is null WHEN notSuppliedCryptoAmountOrNull THEN returns null`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = null,
+ ),
+ amount = BigDecimal.TEN,
+ )
+
+ val result = status.notSuppliedCryptoAmountOrNull()
+
+ assertThat(result).isNull()
+ }
+
+ @Test
+ fun `GIVEN amount is null WHEN notSuppliedCryptoAmountOrNull THEN returns null`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = BigDecimal.TEN,
+ ),
+ amount = null,
+ )
+
+ val result = status.notSuppliedCryptoAmountOrNull()
+
+ assertThat(result).isNull()
+ }
+
+ @Test
+ fun `GIVEN valid data WHEN notSuppliedCryptoAmountOrNull THEN returns amount minus protocolBalance`() {
+ val status = createCryptoCurrencyStatus(
+ currency = mockk(),
+ yieldSupplyStatus = YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = BigDecimal("3"),
+ ),
+ amount = BigDecimal.TEN,
+ )
+
+ val result = status.notSuppliedCryptoAmountOrNull()
+
+ assertThat(result).isEqualTo(BigDecimal("7"))
+ }
+
+ private fun createCryptoCurrencyStatus(
+ currency: CryptoCurrency,
+ yieldSupplyStatus: YieldSupplyStatus? = null,
+ amount: BigDecimal? = null,
+ fiatRate: BigDecimal? = null,
+ ): CryptoCurrencyStatus {
+ val value = mockk {
+ every { this@mockk.yieldSupplyStatus } returns yieldSupplyStatus
+ every { this@mockk.amount } returns amount
+ every { this@mockk.fiatRate } returns fiatRate
+ }
+ return CryptoCurrencyStatus(currency = currency, value = value)
+ }
+}
\ No newline at end of file
diff --git a/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/error/VisaError.kt b/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/error/VisaError.kt
index 4321710d19..412045caff 100644
--- a/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/error/VisaError.kt
+++ b/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/error/VisaError.kt
@@ -65,6 +65,7 @@ sealed class VisaApiError(
data object WithdrawalDataError : VisaApiError(104004003)
data object SignWithdrawError : VisaApiError(104004004)
data object WithdrawError : VisaApiError(104004005)
+ data object ServerUnavailable : VisaApiError(104004006)
companion object {
fun fromBackendError(backendErrorCode: Int): VisaApiError {
diff --git a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetDustMinAmountUseCase.kt b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetDustMinAmountUseCase.kt
index 7814d60add..54ee458d9d 100644
--- a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetDustMinAmountUseCase.kt
+++ b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetDustMinAmountUseCase.kt
@@ -1,15 +1,27 @@
package com.tangem.domain.yield.supply.usecase
import com.tangem.domain.appcurrency.model.AppCurrency
+import com.tangem.domain.models.currency.CryptoCurrencyStatus
import java.math.BigDecimal
+/**
+ * Use case for getting dust minimum amount for yield supply.
+ *
+ * Returns the minimum amount based on the selected [AppCurrency].
+ * If [AppCurrency] is in [SUPPORTED_DUST_CURRENCIES], returns [DUST_MIN_AMOUNT],
+ * otherwise returns the original [minAmount] with trailing zeros stripped.
+ */
class YieldSupplyGetDustMinAmountUseCase {
- operator fun invoke(minAmount: BigDecimal, appCurrency: AppCurrency): BigDecimal {
+ operator fun invoke(
+ minAmountTokenCurrency: BigDecimal,
+ appCurrency: AppCurrency,
+ tokenCryptoCurrencyStatus: CryptoCurrencyStatus,
+ ): BigDecimal {
return if (appCurrency.code in SUPPORTED_DUST_CURRENCIES) {
DUST_MIN_AMOUNT
} else {
- minAmount.stripTrailingZeros()
+ minAmountTokenCurrency.multiply(tokenCryptoCurrencyStatus.value.fiatRate)
}
}
diff --git a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyMinAmountUseCase.kt b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyMinAmountUseCase.kt
index 501e6c74f5..ccb1f53f0d 100644
--- a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyMinAmountUseCase.kt
+++ b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyMinAmountUseCase.kt
@@ -13,6 +13,14 @@ import com.tangem.domain.yield.supply.fixFee
import java.math.BigDecimal
import java.math.RoundingMode
+/**
+ * Use case that calculates the minimum amount required for yield supply operations.
+ *
+ * The calculation is based on the estimated transaction fee converted to the token currency,
+ * with a buffer multiplier applied to account for fee fluctuations.
+ *
+ * @return [BigDecimal] minimum amount in token currency (not native/network currency)
+ */
class YieldSupplyMinAmountUseCase(
private val feeRepository: FeeRepository,
private val quotesRepository: QuotesRepository,
diff --git a/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetDustMinAmountUseCaseTest.kt b/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetDustMinAmountUseCaseTest.kt
index 50a00ac69c..67c35ae602 100644
--- a/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetDustMinAmountUseCaseTest.kt
+++ b/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetDustMinAmountUseCaseTest.kt
@@ -2,6 +2,10 @@ package com.tangem.domain.yield.supply.usecase
import com.google.common.truth.Truth.assertThat
import com.tangem.domain.appcurrency.model.AppCurrency
+import com.tangem.domain.models.currency.CryptoCurrency
+import com.tangem.domain.models.currency.CryptoCurrencyStatus
+import com.tangem.domain.models.network.Network
+import com.tangem.domain.models.network.NetworkAddress
import org.junit.jupiter.api.Test
import java.math.BigDecimal
@@ -13,19 +17,79 @@ class YieldSupplyGetDustMinAmountUseCaseTest {
fun `GIVEN supported currency WHEN invoke THEN return dust min amount`() {
val minAmount = BigDecimal("123.456")
val appCurrency = AppCurrency(code = "EUR", name = "Euro", symbol = "€")
+ val tokenStatus = createTokenStatus(fiatRate = BigDecimal("2.0"))
- val result = useCase(minAmount, appCurrency)
+ val result = useCase(minAmount, appCurrency, tokenStatus)
assertThat(result).isEqualTo(BigDecimal("0.1"))
}
@Test
- fun `GIVEN unsupported currency WHEN invoke THEN return min amount stripped`() {
- val minAmount = BigDecimal("1.2300")
+ fun `GIVEN unsupported currency WHEN invoke THEN return min amount multiplied by fiat rate`() {
+ val minAmount = BigDecimal("1.23")
+ val fiatRate = BigDecimal("150.0")
val appCurrency = AppCurrency(code = "JPY", name = "Japanese Yen", symbol = "¥")
+ val tokenStatus = createTokenStatus(fiatRate = fiatRate)
- val result = useCase(minAmount, appCurrency)
+ val result = useCase(minAmount, appCurrency, tokenStatus)
- assertThat(result).isEqualTo(BigDecimal("1.23"))
+ assertThat(result).isEqualTo(minAmount.multiply(fiatRate))
+ }
+
+ private fun createTokenStatus(fiatRate: BigDecimal): CryptoCurrencyStatus {
+ val network = createNetwork()
+ val token = createToken(network)
+ return CryptoCurrencyStatus(
+ currency = token,
+ value = CryptoCurrencyStatus.Loaded(
+ amount = BigDecimal.ZERO,
+ fiatAmount = BigDecimal.ZERO,
+ fiatRate = fiatRate,
+ priceChange = BigDecimal.ZERO,
+ stakingBalance = null,
+ yieldSupplyStatus = null,
+ hasCurrentNetworkTransactions = false,
+ pendingTransactions = emptySet(),
+ networkAddress = NetworkAddress.Single(
+ NetworkAddress.Address(value = "0xabc", type = NetworkAddress.Address.Type.Primary),
+ ),
+ sources = CryptoCurrencyStatus.Sources(),
+ ),
+ )
+ }
+
+ private fun createNetwork(): Network {
+ val derivationPath = Network.DerivationPath.None
+ return Network(
+ id = Network.ID(Network.RawID("polygon"), derivationPath),
+ backendId = "polygon",
+ name = "Polygon",
+ currencySymbol = "MATIC",
+ derivationPath = derivationPath,
+ isTestnet = false,
+ standardType = Network.StandardType.ERC20,
+ hasFiatFeeRate = false,
+ canHandleTokens = true,
+ transactionExtrasType = Network.TransactionExtrasType.NONE,
+ nameResolvingType = Network.NameResolvingType.ENS,
+ )
+ }
+
+ private fun createToken(network: Network): CryptoCurrency.Token {
+ val tokenId = CryptoCurrency.ID(
+ prefix = CryptoCurrency.ID.Prefix.TOKEN_PREFIX,
+ body = CryptoCurrency.ID.Body.NetworkId(network.rawId),
+ suffix = CryptoCurrency.ID.Suffix.RawID("test-token", "0xContract"),
+ )
+ return CryptoCurrency.Token(
+ id = tokenId,
+ network = network,
+ name = "Test Token",
+ symbol = "TT",
+ decimals = 18,
+ iconUrl = null,
+ isCustom = false,
+ contractAddress = "0xContract",
+ )
}
}
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/StakingRewardsUtils.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/StakingRewardsUtils.kt
index 454a1aa5fb..21af44fe79 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/StakingRewardsUtils.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/StakingRewardsUtils.kt
@@ -47,7 +47,7 @@ internal fun getRewardScheduleText(
-> getCustomRewardSchedule(
networkId = networkId,
decapitalize = decapitalize,
- )
+ ) ?: stringReference(rewardSchedule.name.lowercase().capitalize())
else -> null
}
}
diff --git a/features/token-recieve/impl/src/main/java/com/tangem/features/tokenreceive/entity/TokenReceiveStateFactory.kt b/features/token-recieve/impl/src/main/java/com/tangem/features/tokenreceive/entity/TokenReceiveStateFactory.kt
index ee3dd1a028..bcd955a4af 100644
--- a/features/token-recieve/impl/src/main/java/com/tangem/features/tokenreceive/entity/TokenReceiveStateFactory.kt
+++ b/features/token-recieve/impl/src/main/java/com/tangem/features/tokenreceive/entity/TokenReceiveStateFactory.kt
@@ -6,13 +6,10 @@ import com.tangem.core.ui.R
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.core.ui.components.notifications.NotificationConfig
-import com.tangem.core.ui.extensions.TextReference
-import com.tangem.core.ui.extensions.networkIconResId
-import com.tangem.core.ui.extensions.resourceReference
-import com.tangem.core.ui.extensions.wrappedList
+import com.tangem.core.ui.extensions.*
import com.tangem.domain.models.ReceiveAddressModel
-import com.tangem.domain.models.TokenReceiveType
import com.tangem.domain.models.TokenReceiveNotification
+import com.tangem.domain.models.TokenReceiveType
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.ens.EnsAddress
import com.tangem.features.tokenreceive.entity.ReceiveAddress.Type.Ens
@@ -111,7 +108,10 @@ internal class TokenReceiveStateFactory(
}
ReceiveAddressModel.NameService.Ens -> Ens
ReceiveAddressModel.NameService.Legacy -> Primary.Legacy(
- displayName = TextReference.Res(R.string.domain_receive_assets_legacy_address),
+ displayName = resourceReference(
+ R.string.domain_receive_assets_legacy_address,
+ WrappedList(listOf(cryptoCurrency.name)),
+ ),
)
}
ReceiveAddress(
diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt
index bc5f160b47..21045da86e 100644
--- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt
+++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt
@@ -61,7 +61,7 @@ internal class TxHistoryItemToTransactionStateConverter(
is TransactionType.Swap,
is TransactionType.Transfer,
is TransactionType.UnknownOperation,
- TransactionType.YieldSupply.Send,
+ is TransactionType.YieldSupply.Send,
TransactionType.YieldSupply.Topup,
-> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24
}
@@ -83,10 +83,12 @@ internal class TxHistoryItemToTransactionStateConverter(
is TransactionType.YieldSupply.Enter -> resourceReference(R.string.yield_module_transaction_enter)
is TransactionType.YieldSupply.Exit -> resourceReference(R.string.yield_module_transaction_exit)
TransactionType.YieldSupply.Topup -> resourceReference(R.string.yield_module_transaction_topup)
- TransactionType.YieldSupply.Send -> if (isOutgoing) {
- resourceReference(R.string.common_transfer)
- } else {
- resourceReference(R.string.yield_module_transaction_withdraw)
+ is TransactionType.YieldSupply.Send -> {
+ if (type.isYieldSupplyWithdraw || isOutgoing) {
+ resourceReference(R.string.yield_module_transaction_withdraw)
+ } else {
+ resourceReference(R.string.common_transfer)
+ }
}
is TransactionType.YieldSupply.DeployContract -> resourceReference(
R.string
@@ -107,7 +109,7 @@ internal class TxHistoryItemToTransactionStateConverter(
private fun TxInfo.extractSubtitle(): TextReference {
return when (val type = this.type) {
is TransactionType.YieldSupply -> if (currency is CryptoCurrency.Coin) {
- if (type == TransactionType.YieldSupply.Send) {
+ if (type is TransactionType.YieldSupply.Send) {
extractSubtitleByAddressType()
} else {
resourceReference(
@@ -129,8 +131,8 @@ internal class TxHistoryItemToTransactionStateConverter(
val amount = amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) }
resourceReference(R.string.yield_module_transaction_exit_subtitle, wrappedList(amount))
}
- TransactionType.YieldSupply.Send -> {
- if (isOutgoing) {
+ is TransactionType.YieldSupply.Send -> {
+ if (isOutgoing || !type.isYieldSupplyWithdraw) {
extractSubtitleByAddressType()
} else {
val amount =
@@ -190,12 +192,9 @@ internal class TxHistoryItemToTransactionStateConverter(
TransactionType.Staking.Withdraw,
-> return ""
- is TransactionType.YieldSupply -> if (currency is CryptoCurrency.Token) {
- when (type) {
- TransactionType.YieldSupply.Send -> if (!isOutgoing) {
- return ""
- }
- else -> return ""
+ is TransactionType.YieldSupply -> {
+ if (currency is CryptoCurrency.Token && type == TransactionType.YieldSupply.Send && !isOutgoing) {
+ return ""
}
}
else -> Unit
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt
index a30612c67e..b04f228e55 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt
@@ -71,7 +71,7 @@ internal class TxHistoryItemStateConverter(
is TransactionType.Swap,
is TransactionType.Transfer,
is TransactionType.UnknownOperation,
- TransactionType.YieldSupply.Send,
+ is TransactionType.YieldSupply.Send,
TransactionType.YieldSupply.Topup,
-> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24
}
@@ -93,10 +93,12 @@ internal class TxHistoryItemStateConverter(
is TransactionType.YieldSupply.Enter -> resourceReference(R.string.yield_module_transaction_enter)
is TransactionType.YieldSupply.Exit -> resourceReference(R.string.yield_module_transaction_exit)
TransactionType.YieldSupply.Topup -> resourceReference(R.string.yield_module_transaction_topup)
- TransactionType.YieldSupply.Send -> if (isOutgoing) {
- resourceReference(R.string.common_transfer)
- } else {
- resourceReference(R.string.yield_module_transaction_withdraw)
+ is TransactionType.YieldSupply.Send -> {
+ if (type.isYieldSupplyWithdraw || isOutgoing) {
+ resourceReference(R.string.yield_module_transaction_withdraw)
+ } else {
+ resourceReference(R.string.common_transfer)
+ }
}
is TransactionType.YieldSupply.DeployContract -> resourceReference(
R.string
@@ -137,8 +139,8 @@ internal class TxHistoryItemStateConverter(
wrappedList(amount),
)
}
- TransactionType.YieldSupply.Send -> {
- if (isOutgoing) {
+ is TransactionType.YieldSupply.Send -> {
+ if (isOutgoing || !type.isYieldSupplyWithdraw) {
extractSubtitleByAddressType()
} else {
val amount =
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/YieldSupplyPromoBannerKeyConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/YieldSupplyPromoBannerKeyConverter.kt
index dd2569e500..f335bb30d1 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/YieldSupplyPromoBannerKeyConverter.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/YieldSupplyPromoBannerKeyConverter.kt
@@ -20,16 +20,15 @@ internal class YieldSupplyPromoBannerKeyConverter(
is TokenConverterParams.Wallet -> value.tokenList.flattenCurrencies()
is TokenConverterParams.Account -> value.accountList.flattenCurrencies()
}.filter { status ->
- status.value is CryptoCurrencyStatus.Loaded ||
- status.value is CryptoCurrencyStatus.Custom
+ status.value is CryptoCurrencyStatus.Loaded
}
- val tokens = currencies.filter { it.currency is CryptoCurrency.Token }
+ val cryptoCurrencyStatuses = currencies.filter { it.currency is CryptoCurrency.Token }
- if (tokens.any { it.value.yieldSupplyStatus?.isActive == true }) return null
+ if (cryptoCurrencyStatuses.any { it.value.yieldSupplyStatus?.isActive == true }) return null
if (yieldModuleApyMap.isEmpty()) return null
- val max = tokens.asSequence()
+ val max = cryptoCurrencyStatuses.asSequence()
.mapNotNull { status ->
val token = status.currency as? CryptoCurrency.Token ?: return@mapNotNull null
val tokenKey = token.yieldSupplyKey()
diff --git a/features/wallet/impl/src/test/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/YieldSupplyPromoBannerKeyConverterTest.kt b/features/wallet/impl/src/test/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/YieldSupplyPromoBannerKeyConverterTest.kt
index bca8b45d6e..8584c74aac 100644
--- a/features/wallet/impl/src/test/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/YieldSupplyPromoBannerKeyConverterTest.kt
+++ b/features/wallet/impl/src/test/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/YieldSupplyPromoBannerKeyConverterTest.kt
@@ -20,7 +20,7 @@ class YieldSupplyPromoBannerKeyConverterTest {
@Test
fun `GIVEN promo disabled WHEN convert THEN return null`() {
val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xABCDEF")
- val status = createStatus(token = token, amount = BigDecimal.ONE, isYieldActive = false)
+ val status = createLoadedStatus(token = token, amount = BigDecimal.ONE, isYieldActive = false)
val tokenList = ungroupedTokenList(status)
val params = TokenConverterParams.Wallet(
portfolioId = PortfolioId.Wallet(UserWalletId("00")),
@@ -39,7 +39,7 @@ class YieldSupplyPromoBannerKeyConverterTest {
@Test
fun `GIVEN empty apy map WHEN convert THEN return null`() {
val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xA1")
- val status = createStatus(token = token, amount = BigDecimal("2.0"), isYieldActive = false)
+ val status = createLoadedStatus(token = token, amount = BigDecimal("2.0"), isYieldActive = false)
val params = TokenConverterParams.Wallet(
portfolioId = PortfolioId.Wallet(UserWalletId("00")),
tokenList = ungroupedTokenList(status),
@@ -57,7 +57,7 @@ class YieldSupplyPromoBannerKeyConverterTest {
@Test
fun `GIVEN active yield token present WHEN convert THEN return null`() {
val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xAA")
- val statusActive = createStatus(token = token, amount = BigDecimal("5"), isYieldActive = true)
+ val statusActive = createLoadedStatus(token = token, amount = BigDecimal("5"), isYieldActive = true)
val params = TokenConverterParams.Wallet(
portfolioId = PortfolioId.Wallet(UserWalletId("00")),
tokenList = ungroupedTokenList(statusActive),
@@ -78,8 +78,8 @@ class YieldSupplyPromoBannerKeyConverterTest {
val tokenSmall = createToken(networkId = evmNetworkId, backendId = evmNetworkId, contract = "0xAbCd")
val tokenBig = createToken(networkId = evmNetworkId, backendId = evmNetworkId, contract = "0xBEEF")
- val statusSmall = createStatus(token = tokenSmall, amount = BigDecimal("1.00"), isYieldActive = false)
- val statusBig = createStatus(token = tokenBig, amount = BigDecimal("10.00"), isYieldActive = false)
+ val statusSmall = createLoadedStatus(token = tokenSmall, amount = BigDecimal("1.00"), isYieldActive = false)
+ val statusBig = createLoadedStatus(token = tokenBig, amount = BigDecimal("10.00"), isYieldActive = false)
val apyMap = mapOf(
"${tokenSmall.network.backendId}_${tokenSmall.contractAddress.lowercase()}" to BigDecimal("0.05"),
@@ -105,7 +105,7 @@ class YieldSupplyPromoBannerKeyConverterTest {
fun `GIVEN non evm case sensitive mismatch WHEN convert THEN return null`() {
val nonEvmId = "xrp"
val token = createToken(networkId = nonEvmId, backendId = nonEvmId, contract = "rAbC123")
- val status = createStatus(token = token, amount = BigDecimal("3"), isYieldActive = false)
+ val status = createLoadedStatus(token = token, amount = BigDecimal("3"), isYieldActive = false)
val mismatchedKey = "${token.network.backendId}_${token.contractAddress.lowercase()}"
val apyMap = mapOf(mismatchedKey to BigDecimal("0.07"))
@@ -124,6 +124,24 @@ class YieldSupplyPromoBannerKeyConverterTest {
assertThat(result).isNull()
}
+ @Test
+ fun `GIVEN custom status WHEN convert THEN return null`() {
+ val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xCUSTOM")
+ val status = createCustomStatus(token = token, amount = BigDecimal("5.0"), isYieldActive = false)
+ val params = TokenConverterParams.Wallet(
+ portfolioId = PortfolioId.Wallet(UserWalletId("00")),
+ tokenList = ungroupedTokenList(status),
+ )
+ val converter = YieldSupplyPromoBannerKeyConverter(
+ yieldModuleApyMap = mapOf(token.yieldSupplyKey() to BigDecimal("0.10")),
+ shouldShowMainPromo = true,
+ )
+
+ val result = converter.convert(params)
+
+ assertThat(result).isNull()
+ }
+
private fun ungroupedTokenList(vararg statuses: CryptoCurrencyStatus): TokenList.Ungrouped {
return TokenList.Ungrouped(
totalFiatBalance = com.tangem.domain.models.TotalFiatBalance.Loaded(
@@ -135,7 +153,45 @@ class YieldSupplyPromoBannerKeyConverterTest {
)
}
- private fun createStatus(
+ private fun createLoadedStatus(
+ token: CryptoCurrency.Token,
+ amount: BigDecimal,
+ isYieldActive: Boolean,
+ ): CryptoCurrencyStatus {
+ val networkAddress = NetworkAddress.Single(
+ defaultAddress = NetworkAddress.Address(
+ value = "addr",
+ type = NetworkAddress.Address.Type.Primary,
+ ),
+ )
+ val value = CryptoCurrencyStatus.Loaded(
+ amount = amount,
+ fiatAmount = BigDecimal.ZERO,
+ fiatRate = BigDecimal.ONE,
+ priceChange = BigDecimal.ZERO,
+ stakingBalance = null,
+ yieldSupplyStatus = if (isYieldActive) {
+ YieldSupplyStatus(
+ isActive = true,
+ isInitialized = true,
+ isAllowedToSpend = true,
+ effectiveProtocolBalance = null,
+ )
+ } else {
+ null
+ },
+ hasCurrentNetworkTransactions = false,
+ pendingTransactions = emptySet(),
+ networkAddress = networkAddress,
+ sources = CryptoCurrencyStatus.Sources(),
+ )
+ return CryptoCurrencyStatus(
+ currency = token,
+ value = value,
+ )
+ }
+
+ private fun createCustomStatus(
token: CryptoCurrency.Token,
amount: BigDecimal,
isYieldActive: Boolean,
diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/active/model/YieldSupplyActiveModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/active/model/YieldSupplyActiveModel.kt
index e18a49c84a..3c65576a24 100644
--- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/active/model/YieldSupplyActiveModel.kt
+++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/active/model/YieldSupplyActiveModel.kt
@@ -242,7 +242,11 @@ internal class YieldSupplyActiveModel @Inject constructor(
userWalletId,
cryptoCurrencyStatusFlow.value,
).onRight { minAmount ->
- val dustAmount = yieldSupplyGetDustMinAmountUseCase(minAmount = minAmount, appCurrency = appCurrency)
+ val dustAmount = yieldSupplyGetDustMinAmountUseCase(
+ minAmountTokenCurrency = minAmount,
+ appCurrency = appCurrency,
+ tokenCryptoCurrencyStatus = cryptoCurrencyStatusFlow.value,
+ )
uiState.update(
YieldSupplyActiveMinAmountTransformer(
cryptoCurrencyStatus = cryptoCurrencyStatusFlow.value,
diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/active/model/transformers/YieldSupplyActiveMinAmountTransformer.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/active/model/transformers/YieldSupplyActiveMinAmountTransformer.kt
index 54dd971067..6350642aae 100644
--- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/active/model/transformers/YieldSupplyActiveMinAmountTransformer.kt
+++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/active/model/transformers/YieldSupplyActiveMinAmountTransformer.kt
@@ -11,8 +11,8 @@ import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
-import com.tangem.domain.models.currency.notSuppliedAmountOrNull
-import com.tangem.domain.models.currency.shouldShowNotSuppliedInfoIcon
+import com.tangem.domain.models.currency.notSuppliedCryptoAmountOrNull
+import com.tangem.domain.models.currency.shouldShowNotSuppliedNotification
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
import com.tangem.features.yield.supply.impl.R
import com.tangem.features.yield.supply.impl.active.entity.YieldSupplyActiveContentUM
@@ -91,11 +91,11 @@ internal class YieldSupplyActiveMinAmountTransformer(
}
private fun getNotSuppliedNotification(cryptoCurrencyStatus: CryptoCurrencyStatus): NotificationUM? {
- return if (cryptoCurrencyStatus.shouldShowNotSuppliedInfoIcon(dustMinAmount)) {
+ return if (cryptoCurrencyStatus.shouldShowNotSuppliedNotification(dustMinAmount)) {
val cryptoCurrency = cryptoCurrencyStatus.currency
- val notDepositedAmount = cryptoCurrencyStatus.notSuppliedAmountOrNull()
+ val notSuppliedAmount = cryptoCurrencyStatus.notSuppliedCryptoAmountOrNull()
val formattedAmount =
- notDepositedAmount.format { crypto(symbol = "", decimals = cryptoCurrencyStatus.currency.decimals) }
+ notSuppliedAmount.format { crypto(symbol = "", decimals = cryptoCurrencyStatus.currency.decimals) }
analyticsHandler.send(
YieldSupplyAnalytics.NoticeAmountNotDeposited(
token = cryptoCurrency.symbol,
diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt
index 25e0ab888d..17fba6e4c0 100644
--- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt
+++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt
@@ -19,7 +19,7 @@ import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.currency.hasNotSuppliedAmount
-import com.tangem.domain.models.currency.shouldShowNotSuppliedInfoIcon
+import com.tangem.domain.models.currency.shouldShowNotSuppliedNotification
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
@@ -347,10 +347,11 @@ internal class YieldSupplyModel @Inject constructor(
.getOrNull()
if (minAmount != null) {
val dustAmount = yieldSupplyGetDustMinAmountUseCase(
- minAmount = minAmount,
+ minAmountTokenCurrency = minAmount,
appCurrency = appCurrency,
+ tokenCryptoCurrencyStatus = cryptoCurrencyStatus,
)
- cryptoCurrencyStatus.shouldShowNotSuppliedInfoIcon(dustAmount)
+ cryptoCurrencyStatus.shouldShowNotSuppliedNotification(dustAmount)
} else {
false
}