diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config
index 5b70b3652d..d52c8382e9 160000
--- a/app/src/main/assets/tangem-app-config
+++ b/app/src/main/assets/tangem-app-config
@@ -1 +1 @@
-Subproject commit 5b70b3652d06811e3f1292e41e735e00fe75783f
+Subproject commit d52c8382e9e94b2b44ceecd7cb7bd897e091073c
diff --git a/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt
index bc9b31d6fe..be10ba1059 100644
--- a/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt
+++ b/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt
@@ -152,8 +152,8 @@ internal object StakingDomainModule {
fun provideGetPendingTransactionsUseCase(
stakingPendingTransactionRepository: StakingPendingTransactionRepository,
stakingErrorResolver: StakingErrorResolver,
- ): GetPendingTransactionsUseCase {
- return GetPendingTransactionsUseCase(
+ ): GetStakingPendingTransactionsUseCase {
+ return GetStakingPendingTransactionsUseCase(
stakingPendingTransactionRepository = stakingPendingTransactionRepository,
stakingErrorResolver = stakingErrorResolver,
)
diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/stakekit/models/response/model/YieldDTO.kt b/core/datasource/src/main/java/com/tangem/datasource/api/stakekit/models/response/model/YieldDTO.kt
index 614184aee4..330df3c666 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/api/stakekit/models/response/model/YieldDTO.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/api/stakekit/models/response/model/YieldDTO.kt
@@ -124,7 +124,7 @@ data class YieldDTO(
@Json(name = "rewardSchedule")
val rewardSchedule: RewardScheduleDTO,
@Json(name = "cooldownPeriod")
- val cooldownPeriod: PeriodDTO,
+ val cooldownPeriod: PeriodDTO?,
@Json(name = "warmupPeriod")
val warmupPeriod: PeriodDTO,
@Json(name = "rewardClaiming")
diff --git a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json
index 9e59080422..0aa128c712 100644
--- a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json
+++ b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json
@@ -17,10 +17,10 @@
},
{
"name": "IS_ETHEREUM_EIP_1559_ENABLED",
- "version": "5.16.0"
+ "version": "5.17.0"
},
{
"name": "MIGRATE_USER_COUNTRY_CODE_ENABLED",
- "version": "5.16.0"
+ "version": "5.17.0"
}
]
diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml
index cc96519ec8..516445f46f 100644
--- a/core/res/src/main/res/values-de/strings.xml
+++ b/core/res/src/main/res/values-de/strings.xml
@@ -128,7 +128,7 @@
Keine Adresse
Jetzt
OK
- Primär Karte
+ Hauptkarte
Passphrase
Einfügen
Datenschutzbestimmungen
@@ -275,7 +275,7 @@
Keine Token gefunden. Bitte versuche eine andere Anfrage
ID: %s
Transaktions-ID kopiert
- Wechsel eine Ihrer Währungen in eine andere
+ Tauschen jeden Vermögenswert in Deinem Portfolio gegen diesen Token
Die folgenden Angaben sind freiwillig. Du kannst diese löschen, wenn du sie nicht weitergeben möchtest.
Teile uns mit, welche Funktionen du vermisst, und wir werden versuchen, dir zu helfen.
Bitte sag uns, welche Karte du hast
@@ -345,6 +345,7 @@
Das Wallet unterstützt nicht mehr als ein Netzwerk
Um mit dem Kauf, Tausch oder Erhalt dieses Vermögenswerts zu beginnen, füge diesen Token zu mindestens 1 Netzwerk hinzu
Dieses Asset ist nicht verfügbar
+ Dieses Asset ist für dieses Wallet nicht verfügbar
Zum Portfolio hinzufügen
Hinzufügen
Verfügbare Netzwerke
@@ -561,7 +562,7 @@
- %d Wallet
- %d Wallets
- Zurücksetzen der Karte
+ Karte zurücksetzen
Mir ist bewusst, dass ich nach der Durchführung dieser Aktion keinen Zugriff mehr auf die aktuelle Wallet habe.
Mir ist klar, dass ich diese Karte nicht verwenden kann, um meinen Zugangscode auf den anderen Karten der aktuellen Wallet wiederherzustellen
Durch das Zurücksetzen auf Werkseinstellungen wird die Wallet vollständig von der ausgewählten Karte gelöscht. Du kannst die aktuelle Wallet nicht wiederherstellen oder die Karte verwenden, um den Zugangscode wiederherzustellen.
@@ -686,7 +687,7 @@
Der Zeitraum, den du nach der Beantragung der Abhebung von Geldern aus dem Staking warten musst, bevor die Token verfügbar werden.
Aufwärmphase
Die zugewiesene Zeit für die Aktivierung der Teilnahme am Staking.
- Indem Du die Staking-Funktionalität nutzen, stimmst Du den %1$s und %2$s des Anbieters zu.
+ Indem Du die Staking-Funktionalität nutzt, stimmst Du den %1$s und %2$s des Anbieters zu.
Gesperrt
Migrieren
Natives Staking
@@ -718,14 +719,15 @@
Neuwahl
Automatisch
Händisch
- Block
- Tag
+ Pro Block
+ Täglich
Täglich
- Epoche
- Ära
- Stunde
- Monat
- Woche
+ Alle %1$s Sek.
+ Pro Epoche
+ Pro Ära
+ Stündlich
+ Monatlich
+ Wöchentlich
Belohnungen
Stake gesperrt
Mehr staken
@@ -743,6 +745,7 @@
Unstake Assets %s
Validator/ Prüfer
Validatoren
+ Strategischer Partner
Abstimmung
Abstimmung gesperrt
Zurückziehen
diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml
index 961dbdaafb..ba3e1b02eb 100644
--- a/core/res/src/main/res/values-es/strings.xml
+++ b/core/res/src/main/res/values-es/strings.xml
@@ -338,7 +338,7 @@
Eliminar
por ejemplo, BTC I trust, hodl I must
- Su cartera ha sido actualizada
+ Su portafolio ha sido actualizada
El token seleccionado no está disponible actualmente para acciones dentro de la billetera cripto. Pero no se preocupa, puede expresar su interés votando a favor.
Votar a favor
Elegir wallet
@@ -373,7 +373,7 @@
Compradores experimentados
Evaluación
Ordenar por
- Mejores Ganadores
+ Top Ganadores
Top Perdedores
Tendencias
Acerca de %s
@@ -720,6 +720,7 @@
Bloquear
Día
Cada día
+ Cada %1$s segundo(s)
Época
Era
Hora
@@ -742,8 +743,9 @@
Detenando el staking de activos %s
Validador
Validadores
+ Socio estratégico
Votar
- Voto bloqueado
+ Votar
Retirar
Sus stakes
Almacene sus activos crypto de forma segura manteniendo las claves privadas contenidas en su tarjeta
diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml
index 17c960b9e2..e310d6723c 100644
--- a/core/res/src/main/res/values-fr/strings.xml
+++ b/core/res/src/main/res/values-fr/strings.xml
@@ -720,6 +720,7 @@
Bloquer
Jour
Chaque jour
+ Toute(s) les %1$s seconde(s)
Époque
Ère
Heure
@@ -742,8 +743,9 @@
En train de destaker les actifs %s
Validateur
Validateurs
+ Partenaire stratégique
Voter
- Vote bloqué
+ Voter
Retirer
Vos stakes
Stockez vos actifs crypto en toute sécurité tout en conservant les clés privées contenues dans votre carte
diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml
index 3f051e2972..0d15d6edfc 100644
--- a/core/res/src/main/res/values-ja/strings.xml
+++ b/core/res/src/main/res/values-ja/strings.xml
@@ -95,6 +95,9 @@
- %d 日
+
+ - 日
+
削除
無効
完了
@@ -340,8 +343,9 @@
賛成票を投じる
ウォレットを選択
ウォレットは複数のネットワークをサポートしていません。
- このアセットの購入、交換、受け取りを開始するには、ポートフォリオに追加してください。
+ このアセットを購入・交換・受け取るには、ポートフォリオに追加してください。
このアセットは利用できません
+ このアセットはこのウォレットでは使用できません。
ポートフォリオに追加
追加
利用可能なネットワーク
@@ -388,6 +392,11 @@
取引可能で市場に流通しているコインの総数
循環供給量
取引所が見つかりません
+ 取引所
+ 注意
+ 危険
+ 信頼できる
+ 取引所
経験豊富な買い手
少なくとも100の発信取引を持つネット・バイヤー
経験豊富な買い手
@@ -428,6 +437,7 @@
取引量(24時間)
過去24時間以内に取引された暗号資産の合計額。市場の活発さと流動性を示します。
取引量(24時間)
+ 取引量
これをドラッグするか、検索窓をタップして、マーケットから直接トークンを追加します
トークンを追加
お使いのデバイスではNFCが使用できません
@@ -716,7 +726,10 @@
手動
ブロック毎
毎日
+ %sごと
毎日
+ %1$s日ごとに
+ %1$s秒毎
エポック毎
時代毎
毎時間
@@ -727,6 +740,7 @@
もっとステーキングする
%1$sをステーキングし、年間 %2$sを受け取ります
タップしてロック解除
+ タップしてロック解除もしくは投票
タップして引き出す
%sをステーキングする
%sのステーキング解除
@@ -739,8 +753,9 @@
ステーキング解除中の資産%s
バリデーター
バリデーター
+ 戦略的パートナー
投票する
- 投票はロックされています
+ 投票する
引き出す
あなたのステーキング
カード内に秘密鍵を保管しながら暗号資産を安全に保管します
@@ -804,6 +819,7 @@
オペレーション
送金元: %s
送金先: %s
+ バリデーター: %s
もう一度やり直してください
同じカードをスキャンしました。ツインウォレットを作成するには、番号%dのカードをスキャンする必要があります。
間違ったツインカードをスキャンしました。別のカードをお試しください。
diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 00cebaa9f8..e8db31eab3 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -101,6 +101,12 @@
- %d дней
- %d дней
+
+ - день
+ - дня
+ - дней
+ - дней
+
Удалить
Отключено
Готово
@@ -403,6 +409,9 @@
Циркулирующее предложение
Биржи не найдены
Биржа
+ Осторожно
+ Рискованно
+ Надежно
Биржи
Опытные трейдеры
Покупатели, у которых было как минимум 100 исходящих транзакций.
@@ -445,7 +454,7 @@
Общая сумма криптовалюты, которая была продана за последние 24 часа, показывающая уровень активности и ликвидности на рынке.
Объем торгов (24ч)
Объем
- Потяните вверх или коснитесь поисковой строки, чтобы добавить токены напрямую из маркета
+ Потяните вверх или коснитесь поисковой строки, чтобы добавить токены напрямую из рынка
Добавить токены
Функция NFC недоступна на вашем устройстве
Вам необходимо установить единый код доступа для защиты всех ваших карт
@@ -520,7 +529,7 @@
Подготовьте основную карту с номером %s
Ваша карта настроена и готова к использованию.
Добавлено максимальное количество карт. Завершите процесс резервного копирования.
- Активация карты
+ Активация кошелька
Резервная карта #%d
Нет резервных карт
Уведомления
@@ -745,6 +754,8 @@
За блок
Ежедневно
Каждый день
+ Каждые %1$s дня
+ Каждые %1$s сек
За эпоху
За эру
Ежечасно
@@ -755,6 +766,7 @@
Застейкать еще
Вы стейкаете %1$s и будете получать %2$s ежегодно
Нажмите для разблокировки
+ Нажмите для разблокировки или голосования
Нажмите для вывода
Застейкать %s
Вывести %s
@@ -767,8 +779,9 @@
Завершение стейкинга %s
Валидатор
Валидаторы
+ Стратегический партнер
Проголосовать
- Голосование заблокировано
+ Проголосовать
Вывод
Застейканные средства
Держите свои криптосбережения в безопасности. Приватные ключи надежно хранятся на карте.
diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml
index ef2696c0e6..5a9fb13979 100644
--- a/core/res/src/main/res/values-uk-rUA/strings.xml
+++ b/core/res/src/main/res/values-uk-rUA/strings.xml
@@ -141,7 +141,7 @@
Детальніше
Отримати
Відхилити
- Перезавантажити
+ Оновити
Перейменувати
Зберегти
Зберегти зміни
@@ -351,6 +351,7 @@
Гаманець не підтримує більше однієї мережі
Щоб почати купувати, обмінювати або отримувати цей актив, додайте цей токен принаймні в 1 мережу
Цей актив недоступний
+ Цей токен недоступний для цього гаманця
Додати в портфоліо
Додати
Доступні мережі
@@ -401,6 +402,7 @@
Досвідчені покупці
Повн. розведена кап.
Загальна теоретична вартість криптовалюти, якщо всі монети, які могли б існувати, перебувають в обігу, включаючи ті, що не перебувають в обігу в даний час
+ Повністю розведена капіталізація
Дата створення
Високий
Тримачі
@@ -415,9 +417,11 @@
Низький
Рин. кап.
Загальна ринкова вартість криптовалюти, що розраховується шляхом множення поточної ціни монети на загальну кількість монет в обігу
+ Ринкова капіталізація
Рейтинг
Позиція в крипторейтингу між усіма монетами на основі ринкової капіталізації
Рейтинг
+ Макс. обсяг
Максимальна кількість монет або токенів, яка може коли-небудь існувати для певної криптовалюти
Максимальна пропозиція
Метрики
@@ -713,6 +717,7 @@
Стейкінг дозволяє заробляти %1$s. Ваші винагороди за стейкінг зараховуються щотиждня.
Стейкайте безпечно та почніть отримувати винагороди щотижня
Отримуйте винагороду за стейкінг
+ Стейкінг тимчасово недоступний через проблеми в мережі. Будь ласка, спробуйте пізніше.
Стейкінг в мережі %1$s з новим валідатором автоматично переведе всі раніше застейкані кошти до цього валідатора
Реінвестуйте зароблені винагороди у суму стейкінгу, щоб збільшити потенційний прибуток.
Розблокуйте свої кошти, щоб вивести їх зі стейкінгу. Розблокування займе %s.
@@ -732,6 +737,7 @@
Блок
День
Щодня
+ Кожні %1$s сек
Епоха
Ера
Година
@@ -754,6 +760,7 @@
Виведення зі стейкінгу %s
Валідатор
Валідатори
+ Стратегічний партнер
Проголосувати
Голос заблоковано
Зняти
@@ -813,12 +820,13 @@
Обміняти
контракт: %s
У вас ще немає транзакцій
- Не вдалося завантажити історію транзакцій.\nНатисніть кнопку перезавантаження, щоб оновити інформацію.
+ Не вдалося завантажити історію транзакцій.\nНатисніть кнопку нижче, щоб оновити інформацію
Кілька адрес
Історія транзакцій наразі не підтримується для цього блокчейну. Але не хвилюйтеся, ми працюємо над цим! А поки можете перевірити це в оглядачі.
Операція
від: %s
до: %s
+ валідатор: %s
Спробуйте знову
Ви відсканували одну й ту саму картку. Для створення twin-гаманця вам потрібно відсканувати картку з номером %d
Ви відсканували не ту twin-картку. Будь ласка, спробуйте відсканувати іншу
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index da6e4bbab5..7d4c202a25 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -97,6 +97,10 @@
- %d day
- %d days
+
+ - day
+ - days
+
Delete
Disabled
Done
@@ -128,7 +132,7 @@
No address
Now
OK
- Primary Card
+ Primary card
Passphrase
Paste
Privacy Policy
@@ -511,7 +515,7 @@
Prepare the primary card with number %s
Your wallet card is configured and ready for use.
Max number of cards added. Finalize the backup process.
- Activating card
+ Activating wallet
Backup card #%d
No backup cards
Notifications
@@ -573,7 +577,7 @@
- %d wallet
- %d wallets
- Reset the Card
+ Reset the card
I understand that after performing this action, I will no longer have access to the current wallet
I realize that I can\'t use this card to recover my access code on the other cards of the current wallet
Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code.
@@ -589,7 +593,7 @@
Enable biometric authorization
Would you like to use biometrics?
Note that making a transaction with your funds will still require your card
- Scan Card
+ Scan card
Scan the card to change its settings. The changes will impact only the card you\'ve scanned and will not affect other cards tied to your wallet.
Get your card ready!
Already included in the entered address
@@ -691,7 +695,7 @@
Reward claiming
Method of receiving staking rewards.\nIt can be either automatic, where the reward is credited to your address, or manual, where you need to withdraw the reward by creating a transaction to receive it.
Reward schedule
- This is a schedule that determines when participants in staking receive their rewards.
+ This is a schedule that determines when participants in staking receive their rewards. The reward distribution time may vary slightly depending on the validator and network load.
Rewards: %s
Staking %s
Unbonding Period
@@ -732,7 +736,10 @@
Manual
Per Block
Daily
- Daily
+ Each %s
+ Each day
+ Each %1$s days
+ Each %1$s sec
Per Epoch
Per Era
Hourly
@@ -743,6 +750,7 @@
Stake more
You stake %1$s and will be receiving %2$s yearly
Tap to unlock
+ Tap to unlock or vote
Tap to withdraw
Stake %s
Unstake %s
@@ -755,8 +763,9 @@
Unstaking assets %s
Validator
Validators
+ Strategic partner
Vote
- Vote locked
+ Vote
Withdraw
Your stakes
Store your crypto assets secure while keeping private keys contained in your card
@@ -843,7 +852,7 @@
This wallet has already been saved, you can add another one
The wallet with name %s already exists
Wallet name
- Rename Wallet
+ Rename wallet
Unlock all
Unlock all with %s
Blockchain is unreachable. Try later
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt
index bd65f92ab5..36c14965b1 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt
@@ -24,7 +24,6 @@ import com.tangem.core.ui.components.inputrow.inner.InputRowAsyncImage
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveAnnotatedReference
import com.tangem.core.ui.extensions.resolveReference
-import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
@@ -33,15 +32,17 @@ import com.tangem.core.ui.res.TangemThemePreview
* [Input Row Image](https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=2841-1589&t=u6pOF6lsdpvWLELb-4)
*
* @param subtitle subtitle text
- * @param caption caption text
* @param modifier modifier
+ * @param caption caption text
* @param imageUrl icon to load
+ * @param iconRes icon resource
* @param subtitleColor subtitle text color
* @param captionColor caption text color
+ * @param iconTint icon tint
* @param isGrayscaleImage whether to display grayscale image
- * @param subtitleEndIconRes icon to show after subtitle
* @param iconEndRes icon to end of row
* @param onImageError composable to show if image loading failed
+ * @param subtitleExtraContent subtitle extra content
* @param extraContent extra content
*/
@Suppress("LongMethod")
@@ -56,10 +57,9 @@ internal fun InputRowImageBase(
captionColor: Color = TangemTheme.colors.text.tertiary,
iconTint: Color = TangemTheme.colors.icon.informative,
isGrayscaleImage: Boolean = false,
- @DrawableRes subtitleEndIconRes: Int? = null,
- subtitleEndIconTint: Color = TangemColorPalette.Azure,
@DrawableRes iconEndRes: Int? = null,
onImageError: (@Composable () -> Unit)? = null,
+ subtitleExtraContent: (@Composable RowScope.() -> Unit)? = null,
extraContent: (@Composable RowScope.() -> Unit)? = null,
) {
Row(
@@ -100,10 +100,7 @@ internal fun InputRowImageBase(
style = TangemTheme.typography.subtitle2,
color = subtitleColor,
)
- SubtitleEndIconRes(
- subtitleEndIconRes = subtitleEndIconRes,
- subtitleEndIconTint = subtitleEndIconTint,
- )
+ subtitleExtraContent?.invoke(this)
}
if (caption != null) {
Text(
@@ -124,23 +121,6 @@ internal fun InputRowImageBase(
}
}
-@Composable
-private fun RowScope.SubtitleEndIconRes(subtitleEndIconRes: Int?, subtitleEndIconTint: Color) {
- AnimatedVisibility(
- visible = subtitleEndIconRes != null,
- label = "Subtitle end icon visibility animation",
- modifier = Modifier.align(Alignment.CenterVertically),
- ) {
- val icon = remember(this) { requireNotNull(subtitleEndIconRes) }
- Icon(
- painter = rememberVectorPainter(image = ImageVector.vectorResource(id = icon)),
- tint = subtitleEndIconTint,
- contentDescription = null,
- modifier = Modifier.padding(start = TangemTheme.dimens.spacing4),
- )
- }
-}
-
@Composable
private fun RowScope.InputRowEndIcon(iconRes: Int?) {
AnimatedVisibility(
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageInfo.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageInfo.kt
index 366bd4e48d..c908519e10 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageInfo.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageInfo.kt
@@ -2,14 +2,21 @@ package com.tangem.core.ui.components.inputrow
import android.content.res.Configuration
import androidx.annotation.DrawableRes
+import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.rememberVectorPainter
+import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
@@ -17,6 +24,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.tangem.core.ui.R
import com.tangem.core.ui.components.atoms.text.EllipsisText
import com.tangem.core.ui.extensions.*
+import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
@@ -24,17 +32,19 @@ import com.tangem.core.ui.res.TangemThemePreview
* Input row component with selector
* [Input Row Image](https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=2841-1589&t=u6pOF6lsdpvWLELb-4)
*
- * @param title title text
* @param subtitle subtitle text
- * @param caption caption text
* @param infoTitle info title text
- * @param infoSubtitle info subtitle text
* @param modifier modifier
+ * @param title title text
+ * @param caption caption text
+ * @param infoSubtitle info subtitle text
* @param imageUrl icon to load
+ * @param iconRes icon resource
* @param subtitleColor subtitle text color
* @param captionColor caption text color
+ * @param iconTint icon color
* @param isGrayscaleImage whether to display grayscale image
- * @param showPendingIcon whether to show pending icon
+ * @param subtitleEndIconRes subtitle icon to end of row
* @param iconEndRes icon to end of row
* @param onImageError composable to show if image loading failed
*/
@@ -78,9 +88,14 @@ fun InputRowImageInfo(
subtitleColor = subtitleColor,
captionColor = captionColor,
isGrayscaleImage = isGrayscaleImage,
- subtitleEndIconRes = subtitleEndIconRes,
iconEndRes = iconEndRes,
onImageError = onImageError,
+ subtitleExtraContent = {
+ SubtitleEndIconRes(
+ subtitleEndIconRes = subtitleEndIconRes,
+ subtitleEndIconTint = TangemColorPalette.Azure,
+ )
+ },
) {
Column(
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing2),
@@ -120,6 +135,23 @@ fun InputRowImageInfo(
}
}
+@Composable
+private fun RowScope.SubtitleEndIconRes(subtitleEndIconRes: Int?, subtitleEndIconTint: Color) {
+ AnimatedVisibility(
+ visible = subtitleEndIconRes != null,
+ label = "Subtitle end icon visibility animation",
+ modifier = Modifier.align(Alignment.CenterVertically),
+ ) {
+ val icon = remember(this) { requireNotNull(subtitleEndIconRes) }
+ Icon(
+ painter = rememberVectorPainter(image = ImageVector.vectorResource(id = icon)),
+ tint = subtitleEndIconTint,
+ contentDescription = null,
+ modifier = Modifier.padding(start = TangemTheme.dimens.spacing4),
+ )
+ }
+}
+
// region Preview
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageSelector.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageSelector.kt
index 287edc1197..a9921a83b5 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageSelector.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageSelector.kt
@@ -4,6 +4,7 @@ import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
@@ -40,8 +41,9 @@ import java.math.BigDecimal
* @param subtitleColor subtitle text color
* @param captionColor caption text color
* @param isSelected true if selected
- * @param selectorContent selector content
* @param onImageError composable to show if image loading failed
+ * @param subtitleExtraContent subtitle selector content
+ * @param selectorContent selector content
*/
@Composable
fun InputRowImageSelector(
@@ -54,6 +56,7 @@ fun InputRowImageSelector(
captionColor: Color = TangemTheme.colors.text.tertiary,
isSelected: Boolean = false,
onImageError: (@Composable () -> Unit)? = null,
+ subtitleExtraContent: (@Composable RowScope.() -> Unit)? = null,
selectorContent: @Composable ((isSelected: Boolean, isEnabled: Boolean, onSelect: () -> Unit) -> Unit),
) {
InputRowImageBase(
@@ -63,6 +66,7 @@ fun InputRowImageSelector(
subtitleColor = subtitleColor,
captionColor = captionColor,
onImageError = onImageError,
+ subtitleExtraContent = subtitleExtraContent,
modifier = modifier
.clickable(
onClick = onSelect,
diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt
index 89bffebf60..e468f9d237 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt
@@ -75,6 +75,7 @@ fun getActiveIconRes(blockchainId: String): Int {
"cyber", "cyber/test" -> R.drawable.img_cyber_22
"sei", "sei/test" -> R.drawable.img_sei_22
"internet-computer" -> R.drawable.img_icp_22
+ "sui", "sui/test" -> R.drawable.img_sui_22
"energy-web-chain", "energy-web-chain/test" -> R.drawable.img_energy_web_22
"energy-web-x", "energy-web-x/test" -> R.drawable.img_energy_web_22
else -> R.drawable.ic_alert_24
@@ -153,6 +154,7 @@ fun getActiveIconResByNetworkId(networkId: String): Int {
"cyber", "cyber/test" -> R.drawable.img_cyber_22
"sei", "sei/test" -> R.drawable.img_sei_22
"internet-computer" -> R.drawable.img_icp_22
+ "sui", "sui/test" -> R.drawable.img_sui_22
"energy-web-chain", "energy-web-chain/test" -> R.drawable.img_energy_web_22
"energy-web-x", "energy-web-x/test" -> R.drawable.img_energy_web_22
else -> R.drawable.ic_alert_24
@@ -228,6 +230,7 @@ fun getActiveIconResByCoinId(coinId: String): Int {
"cyber", "cyber/test" -> R.drawable.img_cyber_22
"sei", "sei/test" -> R.drawable.img_sei_22
"internet-computer" -> R.drawable.img_icp_22
+ "sui", "sui/test" -> R.drawable.img_sui_22
"energy-web-chain", "energy-web-chain/test" -> R.drawable.img_energy_web_22
"energy-web-x", "energy-web-x/test" -> R.drawable.img_energy_web_22
else -> R.drawable.ic_alert_24
@@ -306,6 +309,7 @@ fun getGreyedOutIconRes(blockchainId: String): Int {
"cyber", "cyber/test" -> R.drawable.ic_cyber_22
"sei", "sei/test" -> R.drawable.ic_sei_22
"internet-computer" -> R.drawable.ic_icp_22
+ "sui", "sui/test" -> R.drawable.ic_sui_22
"energy-web-chain", "energy-web-chain/test" -> R.drawable.ic_energy_web_22
"energy-web-x", "energy-web-x/test" -> R.drawable.ic_energy_web_22
else -> R.drawable.ic_alert_24
@@ -384,6 +388,7 @@ fun getGreyedOutIconResByNetworkId(networkId: String): Int {
"cyber", "cyber/test" -> R.drawable.ic_cyber_22
"sei", "sei/test" -> R.drawable.ic_sei_22
"internet-computer" -> R.drawable.ic_icp_22
+ "sui", "sui/test" -> R.drawable.ic_sui_22
"energy-web-chain", "energy-web-chain/test" -> R.drawable.ic_energy_web_22
"energy-web-x", "energy-web-x/test" -> R.drawable.ic_energy_web_22
else -> R.drawable.ic_alert_24
diff --git a/core/ui/src/main/res/drawable/ic_sui_22.xml b/core/ui/src/main/res/drawable/ic_sui_22.xml
new file mode 100644
index 0000000000..c6595dd4d7
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_sui_22.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/core/ui/src/main/res/drawable/img_sui_22.xml b/core/ui/src/main/res/drawable/img_sui_22.xml
new file mode 100644
index 0000000000..750a7815c8
--- /dev/null
+++ b/core/ui/src/main/res/drawable/img_sui_22.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt
index b24cbc6210..3c9aabf80e 100644
--- a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt
+++ b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt
@@ -51,8 +51,8 @@ internal class DefaultCustomTokensRepository(
Blockchain.Binance,
Blockchain.BinanceTestnet,
-> true
- Blockchain.Cardano -> blockchain.validateContractAddress(contractAddress.lowercase())
- else -> blockchain.validateAddress(contractAddress.lowercase())
+ Blockchain.Cardano -> blockchain.validateContractAddress(contractAddress)
+ else -> blockchain.validateAddress(contractAddress)
}
}
diff --git a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt
index b0c406b0f5..6ac0700392 100644
--- a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt
+++ b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt
@@ -12,10 +12,12 @@ import com.tangem.data.managetokens.utils.ManagedCryptoCurrencyFactory
import com.tangem.datasource.api.common.response.getOrThrow
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
+import com.tangem.datasource.local.config.testnet.TestnetTokensStorage
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
import com.tangem.datasource.local.userwallet.UserWalletsStore
+import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.extensions.canHandleBlockchain
import com.tangem.domain.common.extensions.canHandleToken
import com.tangem.domain.common.extensions.supportedBlockchains
@@ -30,6 +32,7 @@ import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.pagination.BatchFetchResult
import com.tangem.pagination.BatchListSource
import com.tangem.pagination.fetcher.LimitOffsetBatchFetcher
+import com.tangem.pagination.fetcher.LimitOffsetBatchFetcher.Request
import com.tangem.pagination.toBatchFlow
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@@ -39,6 +42,7 @@ internal class DefaultManageTokensRepository(
private val userWalletsStore: UserWalletsStore,
private val manageTokensUpdateFetcher: ManageTokensUpdateFetcher,
private val appPreferencesStore: AppPreferencesStore,
+ private val testnetTokensStorage: TestnetTokensStorage,
private val dispatchers: CoroutineDispatcherProvider,
) : ManageTokensRepository {
@@ -58,7 +62,6 @@ internal class DefaultManageTokensRepository(
).toBatchFlow()
}
- @Suppress("ComplexCondition")
private fun createFetcher(
batchSize: Int,
): LimitOffsetBatchFetcher> = LimitOffsetBatchFetcher(
@@ -66,59 +69,101 @@ internal class DefaultManageTokensRepository(
batchSize = batchSize,
subFetcher = { request, _, isFirstBatchFetching ->
val userWallet = request.params.userWalletId?.let { getUserWallet(it) }
- val supportedBlockchains = getSupportedBlockchains(userWallet)
- val searchText = request.params.searchText?.takeIf { it.isNotBlank() }
- val call = suspend {
- tangemTechApi.getCoins(
- networkIds = supportedBlockchains.joinToString(
- separator = ",",
- transform = Blockchain::toNetworkId,
- ),
- active = true,
- searchText = searchText,
- offset = request.offset * request.limit,
- limit = request.limit,
- ).getOrThrow()
- }
-
- val coinsResponse = if (isFirstBatchFetching) {
- call()
+ if (userWallet?.scanResponse?.card?.isTestCard == true) {
+ fetchTestnetCurrencies(userWallet, request)
} else {
- retryOnError(call = call)
+ fetchCurrencies(userWallet, request, isFirstBatchFetching)
}
- // filter l2 coins
- val updatedCoinsResponse = coinsResponse.copy(
- coins = coinsResponse.coins.filterNot { l2BlockchainsCoinIds.contains(it.id) },
- )
-
- val tokensResponse = request.params.userWalletId?.let { getSavedUserTokensResponseSync(it) }
- val items = if (isFirstBatchFetching &&
- tokensResponse != null &&
- userWallet != null &&
- request.params.searchText.isNullOrBlank()
- ) {
- managedCryptoCurrencyFactory.createWithCustomTokens(
- coinsResponse = updatedCoinsResponse,
- tokensResponse = tokensResponse,
- scanResponse = userWallet.scanResponse,
- )
- } else {
- managedCryptoCurrencyFactory.create(
- coinsResponse = updatedCoinsResponse,
- tokensResponse = tokensResponse,
- scanResponse = userWallet?.scanResponse,
- )
- }
-
- BatchFetchResult.Success(
- data = items,
- empty = items.isEmpty(),
- last = items.size < request.limit,
- )
},
)
+ @Suppress("ComplexCondition")
+ private suspend fun fetchCurrencies(
+ userWallet: UserWallet?,
+ request: Request,
+ isFirstBatchFetching: Boolean,
+ ): BatchFetchResult.Success> {
+ val supportedBlockchains = getSupportedBlockchains(userWallet)
+
+ val call = suspend {
+ tangemTechApi.getCoins(
+ networkIds = supportedBlockchains.joinToString(
+ separator = ",",
+ transform = Blockchain::toNetworkId,
+ ),
+ active = true,
+ searchText = request.params.searchText,
+ offset = request.offset * request.limit,
+ limit = request.limit,
+ ).getOrThrow()
+ }
+
+ val coinsResponse = if (isFirstBatchFetching) {
+ call()
+ } else {
+ retryOnError(call = call)
+ }
+ // filter l2 coins
+ val updatedCoinsResponse = coinsResponse.copy(
+ coins = coinsResponse.coins.filterNot { l2BlockchainsCoinIds.contains(it.id) },
+ )
+
+ val tokensResponse = request.params.userWalletId?.let { getSavedUserTokensResponseSync(it) }
+ val items = if (isFirstBatchFetching &&
+ tokensResponse != null &&
+ userWallet != null &&
+ request.params.searchText.isNullOrBlank()
+ ) {
+ managedCryptoCurrencyFactory.createWithCustomTokens(
+ coinsResponse = updatedCoinsResponse,
+ tokensResponse = tokensResponse,
+ scanResponse = userWallet.scanResponse,
+ )
+ } else {
+ managedCryptoCurrencyFactory.create(
+ coinsResponse = updatedCoinsResponse,
+ tokensResponse = tokensResponse,
+ scanResponse = userWallet?.scanResponse,
+ )
+ }
+
+ return BatchFetchResult.Success(
+ data = items,
+ empty = items.isEmpty(),
+ last = items.size < request.limit,
+ )
+ }
+
+ private suspend fun fetchTestnetCurrencies(
+ userWallet: UserWallet,
+ request: Request,
+ ): BatchFetchResult.Success> {
+ val searchText = request.params.searchText
+ val testnetTokensConfig = testnetTokensStorage.getConfig()
+
+ val items = managedCryptoCurrencyFactory.createTestnetWithCustomTokens(
+ testnetTokensConfig = if (!searchText.isNullOrBlank()) {
+ testnetTokensConfig.copy(
+ tokens = testnetTokensConfig.tokens.filter { token ->
+ token.symbol.contains(other = searchText, ignoreCase = true) ||
+ token.name.contains(other = searchText, ignoreCase = true)
+ },
+ )
+ } else {
+ testnetTokensConfig
+ },
+ tokensResponse = getSavedUserTokensResponseSync(userWallet.walletId),
+ scanResponse = userWallet.scanResponse,
+ )
+
+ return BatchFetchResult.Success(
+ data = items,
+ empty = items.isEmpty(),
+ last = true,
+ )
+ }
+
private suspend fun getUserWallet(userWalletId: UserWalletId): UserWallet {
return requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
"Unable to find a user wallet with provided ID: $userWalletId"
diff --git a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/di/ManageTokensDataModule.kt b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/di/ManageTokensDataModule.kt
index d5d9009ec3..a85db459dd 100644
--- a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/di/ManageTokensDataModule.kt
+++ b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/di/ManageTokensDataModule.kt
@@ -4,6 +4,7 @@ import com.tangem.data.managetokens.DefaultCustomTokensRepository
import com.tangem.data.managetokens.DefaultManageTokensRepository
import com.tangem.data.managetokens.utils.ManageTokensUpdateFetcher
import com.tangem.datasource.api.tangemTech.TangemTechApi
+import com.tangem.datasource.local.config.testnet.TestnetTokensStorage
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.managetokens.repository.CustomTokensRepository
@@ -27,6 +28,7 @@ internal object ManageTokensDataModule {
userWalletsStore: UserWalletsStore,
manageTokensUpdateFetcher: ManageTokensUpdateFetcher,
appPreferencesStore: AppPreferencesStore,
+ testnetTokensStorage: TestnetTokensStorage,
dispatchers: CoroutineDispatcherProvider,
): ManageTokensRepository {
return DefaultManageTokensRepository(
@@ -34,6 +36,7 @@ internal object ManageTokensDataModule {
userWalletsStore,
manageTokensUpdateFetcher,
appPreferencesStore,
+ testnetTokensStorage,
dispatchers,
)
}
diff --git a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/utils/ManagedCryptoCurrencyFactory.kt b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/utils/ManagedCryptoCurrencyFactory.kt
index ae23245484..31dc2d50e6 100644
--- a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/utils/ManagedCryptoCurrencyFactory.kt
+++ b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/utils/ManagedCryptoCurrencyFactory.kt
@@ -12,6 +12,7 @@ import com.tangem.data.common.currency.getNetwork
import com.tangem.data.common.currency.getTokenId
import com.tangem.datasource.api.tangemTech.models.CoinsResponse
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
+import com.tangem.datasource.local.config.testnet.models.TestnetTokensConfig
import com.tangem.domain.common.DerivationStyleProvider
import com.tangem.domain.common.extensions.canHandleToken
import com.tangem.domain.common.util.cardTypesResolver
@@ -38,20 +39,49 @@ internal class ManagedCryptoCurrencyFactory {
tokensResponse: UserTokensResponse,
scanResponse: ScanResponse,
): List {
- val customTokens = tokensResponse.tokens
- .mapNotNull { token ->
- maybeCreateCustomToken(token, coinsResponse.imageHost, scanResponse)
- }
-
- val tokens = create(
- coinsResponse,
- tokensResponse,
- scanResponse,
- )
+ val customTokens = createCustomTokens(tokensResponse, scanResponse)
+ val tokens = create(coinsResponse, tokensResponse, scanResponse)
return customTokens + tokens
}
+ fun createTestnetWithCustomTokens(
+ testnetTokensConfig: TestnetTokensConfig,
+ tokensResponse: UserTokensResponse?,
+ scanResponse: ScanResponse,
+ ): List {
+ val customTokens = tokensResponse
+ ?.let { createCustomTokens(it, scanResponse) }
+ ?: emptyList()
+ val testnetTokens = testnetTokensConfig.tokens.map { testnetToken ->
+ ManagedCryptoCurrency.Token(
+ id = ManagedCryptoCurrency.ID(testnetToken.id),
+ name = testnetToken.name,
+ symbol = testnetToken.symbol,
+ iconUrl = getIconUrl(testnetToken.id),
+ availableNetworks = testnetToken.networks?.mapNotNull { network ->
+ createSource(
+ networkId = network.id,
+ contractAddress = network.address,
+ decimals = network.decimalCount ?: return@mapNotNull null,
+ scanResponse = scanResponse,
+ )
+ } ?: emptyList(),
+ addedIn = findAddedInNetworks(testnetToken.id, tokensResponse, scanResponse),
+ )
+ }
+
+ return customTokens + testnetTokens
+ }
+
+ private fun createCustomTokens(
+ tokensResponse: UserTokensResponse,
+ scanResponse: ScanResponse,
+ ): List = tokensResponse.tokens
+ .mapNotNull { token ->
+ maybeCreateCustomToken(token, null, scanResponse)
+ }
+
private fun maybeCreateCustomToken(
token: UserTokensResponse.Token,
imageHost: String?,
@@ -108,18 +138,25 @@ internal class ManagedCryptoCurrencyFactory {
symbol = coinResponse.symbol,
iconUrl = getIconUrl(coinResponse.id, imageHost),
availableNetworks = updatedNetworks.mapNotNull { network ->
- createSource(network, scanResponse)
+ createSource(
+ networkId = network.networkId,
+ contractAddress = network.contractAddress,
+ decimals = network.decimalCount?.toInt() ?: return@mapNotNull null,
+ scanResponse = scanResponse,
+ )
},
addedIn = findAddedInNetworks(coinResponse.id, tokensResponse, scanResponse),
)
}
private fun createSource(
- networkResponse: CoinsResponse.Coin.Network,
+ networkId: String,
+ contractAddress: String?,
+ decimals: Int,
scanResponse: ScanResponse?,
extraDerivationPath: String? = null,
): SourceNetwork? {
- val blockchain = Blockchain.fromNetworkId(networkResponse.networkId)
+ val blockchain = Blockchain.fromNetworkId(networkId)
?.takeIf { it.isSupportedInApp() }
?: return null
@@ -131,7 +168,6 @@ internal class ManagedCryptoCurrencyFactory {
it.card.canHandleToken(blockchain, it.cardTypesResolver)
} ?: true,
) ?: return null
- val contractAddress = networkResponse.contractAddress
return if (contractAddress.isNullOrBlank()) {
SourceNetwork.Main(
@@ -142,7 +178,7 @@ internal class ManagedCryptoCurrencyFactory {
} else {
SourceNetwork.Default(
network = network,
- decimals = requireNotNull(networkResponse.decimalCount?.toInt()),
+ decimals = decimals,
contractAddress = contractAddress,
)
}
@@ -175,7 +211,7 @@ internal class ManagedCryptoCurrencyFactory {
}
}
- private fun getIconUrl(id: String, imageHost: String?): String {
+ private fun getIconUrl(id: String, imageHost: String? = DEFAULT_IMAGE_HOST): String {
return "${imageHost ?: DEFAULT_IMAGE_HOST}large/$id.png"
}
diff --git a/data/markets/src/main/java/com/tangem/data/markets/DefaultMarketsTokenRepository.kt b/data/markets/src/main/java/com/tangem/data/markets/DefaultMarketsTokenRepository.kt
index a46ce3dda8..2a8c0ed1d7 100644
--- a/data/markets/src/main/java/com/tangem/data/markets/DefaultMarketsTokenRepository.kt
+++ b/data/markets/src/main/java/com/tangem/data/markets/DefaultMarketsTokenRepository.kt
@@ -120,7 +120,7 @@ internal class DefaultMarketsTokenRepository(
interval: PriceChangeInterval,
tokenId: String,
tokenSymbol: String,
- ): TokenChart {
+ ) = withContext(dispatcherProvider.io) {
val mappedTokenId = getTokenIdIfL2Network(tokenId)
val response = marketsApi.getCoinChart(
currency = fiatCurrencyCode,
@@ -137,7 +137,7 @@ internal class DefaultMarketsTokenRepository(
response.getOrThrow()
}
- return TokenChartConverter.convert(
+ return@withContext TokenChartConverter.convert(
interval = interval,
value = result,
@@ -157,7 +157,7 @@ internal class DefaultMarketsTokenRepository(
interval: PriceChangeInterval,
tokenId: String,
tokenSymbol: String,
- ): TokenChart {
+ ) = withContext(dispatcherProvider.io) {
val mappedTokenId = getTokenIdIfL2Network(tokenId)
val response = marketsApi.getCoinsListCharts(
coinIds = mappedTokenId,
@@ -171,7 +171,7 @@ internal class DefaultMarketsTokenRepository(
)
}
- return TokenChartConverter.convert(
+ return@withContext TokenChartConverter.convert(
interval = interval,
value = chart,
@@ -191,7 +191,7 @@ internal class DefaultMarketsTokenRepository(
tokenId: String,
tokenSymbol: String,
languageCode: String,
- ): TokenMarketInfo {
+ ) = withContext(dispatcherProvider.io) {
val response = marketsApi.getCoinMarketData(
currency = fiatCurrencyCode,
coinId = tokenId,
@@ -208,29 +208,30 @@ internal class DefaultMarketsTokenRepository(
}
val resultResponse = result.applyL2Compatibility(tokenId)
- return TokenMarketInfoConverter.convert(resultResponse)
+ return@withContext TokenMarketInfoConverter.convert(resultResponse)
}
- override suspend fun getTokenQuotes(fiatCurrencyCode: String, tokenId: String, tokenSymbol: String): TokenQuotes {
- // for second markets iteration we should use extended api method with all required fields
- val response = tangemTechApi.getQuotes(
- currencyId = fiatCurrencyCode,
- coinIds = tokenId,
- fields = marketsQuoteFields.joinToString(separator = ","),
- )
+ override suspend fun getTokenQuotes(fiatCurrencyCode: String, tokenId: String, tokenSymbol: String) =
+ withContext(dispatcherProvider.io) {
+ // for second markets iteration we should use extended api method with all required fields
+ val response = tangemTechApi.getQuotes(
+ currencyId = fiatCurrencyCode,
+ coinIds = tokenId,
+ fields = marketsQuoteFields.joinToString(separator = ","),
+ )
- val result = catchApiErrorAndSendEvent(
- errorEvent = MarketsDataAnalyticsEvent.Details.Error(
- request = MarketsDataAnalyticsEvent.Details.Error.Request.Info,
- tokenSymbol = tokenSymbol,
- ),
- ) {
- response.getOrThrow()
+ val result = catchApiErrorAndSendEvent(
+ errorEvent = MarketsDataAnalyticsEvent.Details.Error(
+ request = MarketsDataAnalyticsEvent.Details.Error.Request.Info,
+ tokenSymbol = tokenSymbol,
+ ),
+ ) {
+ response.getOrThrow()
+ }
+
+ return@withContext TokenQuotesShortConverter.convert(tokenId, result).toFull()
}
- return TokenQuotesShortConverter.convert(tokenId, result).toFull()
- }
-
override suspend fun createCryptoCurrency(
userWalletId: UserWalletId,
token: TokenMarketParams,
diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingPendingTransactionRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingPendingTransactionRepository.kt
index 0b637744ab..008ea7161a 100644
--- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingPendingTransactionRepository.kt
+++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingPendingTransactionRepository.kt
@@ -3,25 +3,30 @@ package com.tangem.data.staking
import com.tangem.domain.staking.model.PendingTransaction
import com.tangem.domain.staking.model.stakekit.BalanceItem
import com.tangem.domain.staking.repositories.StakingPendingTransactionRepository
+import com.tangem.domain.wallets.models.UserWalletId
+import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArrayList
internal class DefaultStakingPendingTransactionRepository : StakingPendingTransactionRepository {
- private val pendingTransactions = CopyOnWriteArrayList()
+ private val pendingTransactionsMap = ConcurrentHashMap>()
- override fun saveTransaction(transaction: PendingTransaction) {
- pendingTransactions.add(transaction)
+ override fun saveTransaction(userWalletId: UserWalletId, transaction: PendingTransaction) {
+ val transactions = pendingTransactionsMap.computeIfAbsent(userWalletId) { CopyOnWriteArrayList() }
+ transactions.add(transaction)
}
- override fun removeTransactions(transactions: Set) {
- pendingTransactions.removeAll(transactions)
+ override fun removeTransactions(userWalletId: UserWalletId, transactions: Set) {
+ pendingTransactionsMap[userWalletId]?.removeAll(transactions)
}
- override fun getTransactionsWithBalanceItems(): List> {
- return pendingTransactions.mapNotNull { pendingTransaction ->
+ override fun getTransactionsWithBalanceItems(
+ userWalletId: UserWalletId,
+ ): List> {
+ return pendingTransactionsMap[userWalletId]?.mapNotNull { pendingTransaction: PendingTransaction ->
PendingTransactionItemConverter.convert(pendingTransaction)?.let { balanceItem ->
pendingTransaction to balanceItem
}
- }
+ } ?: emptyList()
}
}
\ No newline at end of file
diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt
index c21f12dc95..539eb7ee4e 100644
--- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt
+++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt
@@ -98,8 +98,7 @@ internal class DefaultStakingRepository(
)
private val yieldBalanceConverter = YieldBalanceConverter()
-
- private val yieldBalanceListConverter = YieldBalanceListConverter()
+ private val yieldBalanceListConverter = YieldBalanceListConverter(yieldBalanceConverter)
private val isYieldBalanceFetching = MutableStateFlow(
value = emptyMap(),
@@ -121,7 +120,7 @@ internal class DefaultStakingRepository(
key = YIELDS_STORE_KEY,
skipCache = refresh,
block = {
- val stakingTokensWithYields = stakeKitApi.getEnabledYields(preferredValidatorsOnly = true)
+ val stakingTokensWithYields = stakeKitApi.getEnabledYields(preferredValidatorsOnly = false)
.getOrThrow()
stakingYieldsStore.store(stakingTokensWithYields.data)
diff --git a/data/staking/src/main/java/com/tangem/data/staking/PendingTransactionItemConverter.kt b/data/staking/src/main/java/com/tangem/data/staking/PendingTransactionItemConverter.kt
index a18b61f591..6169fc2b96 100644
--- a/data/staking/src/main/java/com/tangem/data/staking/PendingTransactionItemConverter.kt
+++ b/data/staking/src/main/java/com/tangem/data/staking/PendingTransactionItemConverter.kt
@@ -10,8 +10,8 @@ internal object PendingTransactionItemConverter : Converter {
@@ -27,9 +26,7 @@ internal class YieldBalanceConverter : Converter, YieldBalanceList> {
-
- internal val converter by lazy(LazyThreadSafetyMode.NONE) {
- YieldBalanceConverter()
- }
+internal class YieldBalanceListConverter(
+ private val yieldBalanceConverter: YieldBalanceConverter,
+) : Converter, YieldBalanceList> {
override fun convert(value: Set): YieldBalanceList {
return if (value.isEmpty()) {
YieldBalanceList.Empty
} else {
YieldBalanceList.Data(
- balances = value.map(converter::convert),
+ balances = value.map(yieldBalanceConverter::convert),
)
}
}
diff --git a/data/staking/src/main/java/com/tangem/data/staking/converters/YieldConverter.kt b/data/staking/src/main/java/com/tangem/data/staking/converters/YieldConverter.kt
index c08359c098..7499cb4a34 100644
--- a/data/staking/src/main/java/com/tangem/data/staking/converters/YieldConverter.kt
+++ b/data/staking/src/main/java/com/tangem/data/staking/converters/YieldConverter.kt
@@ -28,7 +28,7 @@ class YieldConverter(
metadata = convertMetadata(value.metadata),
validators = value.validators
.asSequence()
- .filter { it.preferred && it.status == ValidatorStatusDTO.ACTIVE }
+ .filter { it.status == ValidatorStatusDTO.ACTIVE }
.sortedByDescending { it.apr }
.map { convertValidator(it) }
.toImmutableList(),
@@ -88,7 +88,7 @@ class YieldConverter(
tokens = metadataDTO.tokensDTO.map { tokenConverter.convert(it) },
type = metadataDTO.type,
rewardSchedule = convertRewardSchedule(metadataDTO.rewardSchedule),
- cooldownPeriod = convertPeriod(metadataDTO.cooldownPeriod),
+ cooldownPeriod = metadataDTO.cooldownPeriod?.let { convertPeriod(it) },
warmupPeriod = convertPeriod(metadataDTO.warmupPeriod),
rewardClaiming = convertRewardClaiming(metadataDTO.rewardClaiming),
defaultValidator = metadataDTO.defaultValidator,
@@ -123,6 +123,7 @@ class YieldConverter(
stakedBalance = validatorDTO.stakedBalance,
votingPower = validatorDTO.votingPower,
preferred = validatorDTO.preferred,
+ isStrategicPartner = isStrategicPartner(validatorDTO.address),
)
}
@@ -174,4 +175,12 @@ class YieldConverter(
else -> Yield.Args.ArgType.UNKNOWN
}
}
+
+ private fun isStrategicPartner(validatorAddress: String): Boolean = PARTNERS.any { it == validatorAddress }
+
+ private companion object {
+ val PARTNERS = listOf(
+ "cosmosvaloper1wrx0x9m9ykdhw9sg04v7uljme53wuj03aa5d4f",
+ )
+ }
}
\ No newline at end of file
diff --git a/data/transaction/src/main/java/com/tangem/data/transaction/DefaultTransactionRepository.kt b/data/transaction/src/main/java/com/tangem/data/transaction/DefaultTransactionRepository.kt
index 0452da5a7c..b18a5b0fa4 100644
--- a/data/transaction/src/main/java/com/tangem/data/transaction/DefaultTransactionRepository.kt
+++ b/data/transaction/src/main/java/com/tangem/data/transaction/DefaultTransactionRepository.kt
@@ -6,6 +6,7 @@ import com.tangem.blockchain.blockchains.binance.BinanceTransactionExtras
import com.tangem.blockchain.blockchains.cosmos.CosmosTransactionExtras
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
import com.tangem.blockchain.blockchains.hedera.HederaTransactionExtras
+import com.tangem.blockchain.blockchains.icp.ICPTransactionExtras
import com.tangem.blockchain.blockchains.stellar.StellarMemo
import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras
import com.tangem.blockchain.blockchains.ton.TonTransactionExtras
@@ -249,6 +250,7 @@ internal class DefaultTransactionRepository(
)
}
+ @Suppress("CyclomaticComplexMethod")
private fun getMemoExtras(networkId: String, memo: String?): TransactionExtras? {
val blockchain = Blockchain.fromId(networkId)
if (memo == null) return null
@@ -263,12 +265,14 @@ internal class DefaultTransactionRepository(
Blockchain.Binance -> BinanceTransactionExtras(memo)
Blockchain.XRP -> memo.toLongOrNull()?.let { XrpTransactionBuilder.XrpTransactionExtras(it) }
Blockchain.Cosmos,
+ Blockchain.Sei,
Blockchain.TerraV1,
Blockchain.TerraV2,
-> CosmosTransactionExtras(memo)
Blockchain.TON -> TonTransactionExtras(memo)
Blockchain.Hedera -> HederaTransactionExtras(memo)
Blockchain.Algorand -> AlgorandTransactionExtras(memo)
+ Blockchain.InternetComputer -> memo.toLongOrNull()?.let { ICPTransactionExtras(it) }
else -> null
}
}
diff --git a/domain/staking/build.gradle.kts b/domain/staking/build.gradle.kts
index dd1083b53b..5107e30cf7 100644
--- a/domain/staking/build.gradle.kts
+++ b/domain/staking/build.gradle.kts
@@ -11,9 +11,10 @@ android {
dependencies {
api(projects.domain.staking.models)
-
api(projects.domain.core)
+
implementation(deps.kotlin.serialization)
+ implementation(deps.jodatime)
implementation(projects.domain.tokens.models)
implementation(projects.domain.wallets.models)
diff --git a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/PendingTransaction.kt b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/PendingTransaction.kt
index b1d1c6bd1c..b01eab990b 100644
--- a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/PendingTransaction.kt
+++ b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/PendingTransaction.kt
@@ -6,8 +6,9 @@ import java.math.BigDecimal
data class PendingTransaction(
val groupId: String?,
- val type: BalanceType?,
- val amount: BigDecimal?,
+ val type: BalanceType,
+ val amount: BigDecimal,
val rawCurrencyId: String?,
val validator: Yield.Validator?,
+ val balancesId: Int,
)
\ No newline at end of file
diff --git a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/SubmitHashData.kt b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/SubmitHashData.kt
index b66b653fa3..684264334d 100644
--- a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/SubmitHashData.kt
+++ b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/SubmitHashData.kt
@@ -1,14 +1,7 @@
package com.tangem.domain.staking.model
-import com.tangem.domain.staking.model.stakekit.BalanceType
-import com.tangem.domain.staking.model.stakekit.Yield
-import java.math.BigDecimal
-
data class SubmitHashData(
val transactionHash: String,
val transactionId: String,
- val validator: Yield.Validator?,
- val amount: BigDecimal?,
- val balanceType: BalanceType?,
- val rawCurrencyId: String?,
+ val pendingTransaction: PendingTransaction,
)
\ No newline at end of file
diff --git a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/Yield.kt b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/Yield.kt
index 4be9bad438..768d65cbf4 100644
--- a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/Yield.kt
+++ b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/Yield.kt
@@ -62,6 +62,7 @@ data class Yield(
val stakedBalance: String? = null,
val votingPower: Double? = null,
val preferred: Boolean,
+ val isStrategicPartner: Boolean,
) {
enum class ValidatorStatus {
@@ -84,7 +85,7 @@ data class Yield(
val tokens: List,
val type: String,
val rewardSchedule: RewardSchedule,
- val cooldownPeriod: Period,
+ val cooldownPeriod: Period?,
val warmupPeriod: Period,
val rewardClaiming: RewardClaiming,
val defaultValidator: String?,
diff --git a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/YieldBalance.kt b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/YieldBalance.kt
index 8baf77fcd3..01ac5388c9 100644
--- a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/YieldBalance.kt
+++ b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/YieldBalance.kt
@@ -32,6 +32,14 @@ sealed class YieldBalance {
.distinctBy { it.validatorAddress }
.size
}
+
+ fun getBalancesUniqueId(): Int {
+ // need to exclude rewards because their amount may change frequently
+ return balance.items
+ .filter { it.type != BalanceType.REWARDS }
+ .map { it.amount.toString() + it.type.toString() + it.groupId }
+ .hashCode()
+ }
}
data object Empty : YieldBalance()
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/GetPendingTransactionsUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingPendingTransactionsUseCase.kt
similarity index 75%
rename from domain/staking/src/main/java/com/tangem/domain/staking/GetPendingTransactionsUseCase.kt
rename to domain/staking/src/main/java/com/tangem/domain/staking/GetStakingPendingTransactionsUseCase.kt
index 1f4be9dea2..15557232b0 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/GetPendingTransactionsUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingPendingTransactionsUseCase.kt
@@ -5,18 +5,19 @@ import com.tangem.domain.staking.model.stakekit.BalanceItem
import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.repositories.StakingErrorResolver
import com.tangem.domain.staking.repositories.StakingPendingTransactionRepository
+import com.tangem.domain.wallets.models.UserWalletId
/**
* Use case for getting saved staking pending transactions.
*/
-class GetPendingTransactionsUseCase(
+class GetStakingPendingTransactionsUseCase(
private val stakingPendingTransactionRepository: StakingPendingTransactionRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
- operator fun invoke(): Either> {
+ operator fun invoke(userWalletId: UserWalletId): Either> {
return Either.catch {
- stakingPendingTransactionRepository.getTransactionsWithBalanceItems().map { it.second }
+ stakingPendingTransactionRepository.getTransactionsWithBalanceItems(userWalletId).map { it.second }
}.mapLeft {
stakingErrorResolver.resolve(it)
}
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/InvalidatePendingTransactionsUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/InvalidatePendingTransactionsUseCase.kt
index daddce0ad9..b7c4c597ef 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/InvalidatePendingTransactionsUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/InvalidatePendingTransactionsUseCase.kt
@@ -3,52 +3,74 @@ package com.tangem.domain.staking
import arrow.core.Either
import com.tangem.domain.staking.model.PendingTransaction
import com.tangem.domain.staking.model.stakekit.BalanceItem
+import com.tangem.domain.staking.model.stakekit.BalanceType
import com.tangem.domain.staking.model.stakekit.StakingError
-import com.tangem.domain.staking.model.stakekit.YieldBalance
import com.tangem.domain.staking.repositories.StakingErrorResolver
import com.tangem.domain.staking.repositories.StakingPendingTransactionRepository
+import com.tangem.domain.wallets.models.UserWalletId
+import java.util.UUID
class InvalidatePendingTransactionsUseCase(
private val stakingPendingTransactionRepository: StakingPendingTransactionRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
- operator fun invoke(yieldBalance: YieldBalance): Either> {
+ operator fun invoke(
+ userWalletId: UserWalletId,
+ balanceItems: List,
+ balancesId: Int,
+ ): Either> {
return Either.catch {
- if (yieldBalance is YieldBalance.Data) {
- val (balancesToDisplay, transactionsToRemove) = mergeRealAndPendingTransactions(
- real = yieldBalance.balance.items,
- pending = stakingPendingTransactionRepository.getTransactionsWithBalanceItems(),
- )
+ val (balancesToDisplay, transactionsToRemove) = mergeRealAndPendingTransactions(
+ realData = balanceItems,
+ newBalancesId = balancesId,
+ pendingData = stakingPendingTransactionRepository.getTransactionsWithBalanceItems(userWalletId),
+ )
- stakingPendingTransactionRepository.removeTransactions(transactionsToRemove.toSet())
+ stakingPendingTransactionRepository.removeTransactions(userWalletId, transactionsToRemove.toSet())
- balancesToDisplay
- } else {
- emptyList()
- }
+ balancesToDisplay
}.mapLeft {
stakingErrorResolver.resolve(it)
}
}
private fun mergeRealAndPendingTransactions(
- real: List,
- pending: List>,
+ realData: List,
+ newBalancesId: Int,
+ pendingData: List>,
): Pair, List> {
- val map = real.associateBy { Triple(it.groupId, it.type, it.amount) }.toMutableMap()
+ val balances = realData.associateBy { Triple(it.groupId, it.type, it.amount) }.toMutableMap()
- val toRemove = mutableListOf()
+ val transactionsToRemove = mutableListOf()
- pending.forEach { (pendingTransaction, balanceItem) ->
+ pendingData.forEach { (pendingTransaction, balanceItem) ->
val key = Triple(balanceItem.groupId, balanceItem.type, balanceItem.amount)
- if (map.containsKey(key)) {
- map[key] = balanceItem
- } else {
- toRemove.add(pendingTransaction)
+ val oldBalancesId = pendingTransaction.balancesId
+
+ when {
+ newBalancesId != oldBalancesId -> {
+ transactionsToRemove.add(pendingTransaction)
+ }
+ balances.containsKey(key) -> {
+ balances[key] = balanceItem
+ }
+ else -> {
+ val groupId = UUID.randomUUID().toString()
+ balances[Triple(groupId, BalanceType.STAKED, pendingTransaction.amount)] = BalanceItem(
+ groupId = groupId,
+ type = pendingTransaction.type,
+ amount = pendingTransaction.amount,
+ rawCurrencyId = pendingTransaction.rawCurrencyId,
+ validatorAddress = pendingTransaction.validator?.address,
+ date = null,
+ pendingActions = emptyList(),
+ isPending = true,
+ )
+ }
}
}
- return map.values.toList() to toRemove
+ return balances.values.toList() to transactionsToRemove
}
}
\ No newline at end of file
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/SavePendingTransactionUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/SavePendingTransactionUseCase.kt
index 64ce855ae5..ef80e06e64 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/SavePendingTransactionUseCase.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/SavePendingTransactionUseCase.kt
@@ -5,6 +5,7 @@ import com.tangem.domain.staking.model.PendingTransaction
import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.repositories.StakingErrorResolver
import com.tangem.domain.staking.repositories.StakingPendingTransactionRepository
+import com.tangem.domain.wallets.models.UserWalletId
/**
* Use case for saving hash that failed to submit during staking confirmation
@@ -14,9 +15,12 @@ class SavePendingTransactionUseCase(
private val stakingErrorResolver: StakingErrorResolver,
) {
- operator fun invoke(pendingTransaction: PendingTransaction): Either {
+ operator fun invoke(userWalletId: UserWalletId, transaction: PendingTransaction): Either {
return Either.catch {
- stakingPendingTransactionRepository.saveTransaction(pendingTransaction)
+ stakingPendingTransactionRepository.saveTransaction(
+ userWalletId = userWalletId,
+ transaction = transaction,
+ )
}.mapLeft {
stakingErrorResolver.resolve(it)
}
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingPendingTransactionRepository.kt b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingPendingTransactionRepository.kt
index 02bb96806b..708b8e1352 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingPendingTransactionRepository.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingPendingTransactionRepository.kt
@@ -2,12 +2,13 @@ package com.tangem.domain.staking.repositories
import com.tangem.domain.staking.model.PendingTransaction
import com.tangem.domain.staking.model.stakekit.BalanceItem
+import com.tangem.domain.wallets.models.UserWalletId
interface StakingPendingTransactionRepository {
- fun getTransactionsWithBalanceItems(): List>
+ fun getTransactionsWithBalanceItems(userWalletId: UserWalletId): List>
- fun saveTransaction(transaction: PendingTransaction)
+ fun saveTransaction(userWalletId: UserWalletId, transaction: PendingTransaction)
- fun removeTransactions(transactions: Set)
+ fun removeTransactions(userWalletId: UserWalletId, transactions: Set)
}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientMemoFieldConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientMemoFieldConverter.kt
index 1525d0d6ab..5c9e9b0679 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientMemoFieldConverter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientMemoFieldConverter.kt
@@ -36,6 +36,8 @@ internal class SendRecipientMemoFieldConverter(
Blockchain.Stellar.id,
Blockchain.Hedera.id,
Blockchain.Algorand.id,
+ Blockchain.Sei.id,
+ Blockchain.InternetComputer.id,
-> {
convert(
value = Data(memo = memo, label = R.string.send_extras_hint_memo),
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingNotification.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingNotification.kt
index c989a34d8c..8472172758 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingNotification.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingNotification.kt
@@ -85,17 +85,12 @@ internal object StakingNotification {
),
)
- data class PendingAction(
+ data class Ordinary(
val title: TextReference,
val text: TextReference,
) : StakingNotification.Info(
title = title,
subtitle = text,
)
-
- data object TronRevote : StakingNotification.Info(
- title = resourceReference(R.string.staking_revote),
- subtitle = resourceReference(R.string.staking_notifications_revote_tron_text),
- )
}
}
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt
index c490284116..4bc8b84bda 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt
@@ -9,6 +9,7 @@ import com.tangem.core.ui.components.list.RoundedListWithDividersItemData
import com.tangem.core.ui.event.StateEvent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.pullToRefresh.PullToRefreshConfig
+import com.tangem.domain.staking.model.PendingTransaction
import com.tangem.domain.staking.model.stakekit.PendingAction
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType
@@ -98,7 +99,7 @@ internal sealed class StakingStates {
val transactionDoneState: TransactionDoneState,
val isApprovalNeeded: Boolean,
val reduceAmountBy: BigDecimal?,
- val balanceState: BalanceState?,
+ val possiblePendingTransaction: PendingTransaction?,
) : ConfirmationState()
data class Empty(
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/BalanceItemConverter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/BalanceItemConverter.kt
index 141759adfb..045baf45e0 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/BalanceItemConverter.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/BalanceItemConverter.kt
@@ -8,6 +8,7 @@ import com.tangem.domain.staking.model.stakekit.BalanceItem
import com.tangem.domain.staking.model.stakekit.BalanceType
import com.tangem.domain.staking.model.stakekit.BalanceType.Companion.isClickable
import com.tangem.domain.staking.model.stakekit.Yield
+import com.tangem.domain.staking.model.stakekit.action.StakingActionType
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.staking.impl.R
import com.tangem.features.staking.impl.presentation.state.BalanceState
@@ -83,7 +84,11 @@ internal class BalanceItemConverter(
private fun getSubtitle(balance: BalanceItem) = when (balance.type) {
BalanceType.UNSTAKING -> getUnbondingDate(balance.date)
BalanceType.UNSTAKED -> resourceReference(R.string.staking_tap_to_withdraw)
- BalanceType.LOCKED -> resourceReference(R.string.staking_tap_to_unlock)
+ BalanceType.LOCKED -> if (balance.pendingActions.any { it.type == StakingActionType.VOTE_LOCKED }) {
+ resourceReference(R.string.staking_tap_to_unlock_or_vote)
+ } else {
+ resourceReference(R.string.staking_tap_to_unlock)
+ }
BalanceType.PREPARING -> {
val warmupPeriod = yield.metadata.warmupPeriod.days
combinedReference(
@@ -100,8 +105,8 @@ internal class BalanceItemConverter(
-> null
}
- private fun getUnbondingDate(date: DateTime?): TextReference {
- val unbondingPeriod = yield.metadata.cooldownPeriod.days
+ private fun getUnbondingDate(date: DateTime?): TextReference? {
+ val unbondingPeriod = yield.metadata.cooldownPeriod?.days ?: return null
if (date == null) {
return combinedReference(
resourceReference(R.string.staking_details_unbonding_period),
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/YieldBalancesConverter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/YieldBalancesConverter.kt
index 5c82de46c3..fc1f8a834e 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/YieldBalancesConverter.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/YieldBalancesConverter.kt
@@ -28,12 +28,17 @@ internal class YieldBalancesConverter(
val cryptoCurrency = cryptoCurrencyStatus.currency
val yieldBalance = cryptoCurrencyStatus.value.yieldBalance
+ val balanceToShowItems = balancesToShowProvider()
- return if (yieldBalance is YieldBalance.Data) {
- val cryptoRewardsValue = yieldBalance.getRewardStakingBalance()
- val fiatRewardsValue = cryptoCurrencyStatus.value.fiatRate?.times(cryptoRewardsValue)
+ return if (yieldBalance is YieldBalance.Data || balanceToShowItems.any { it.isPending }) {
+ val cryptoRewardsValue = (yieldBalance as? YieldBalance.Data)?.getRewardStakingBalance()
- val balanceToShowItems = balancesToShowProvider()
+ val fiatRate = cryptoCurrencyStatus.value.fiatRate
+ val fiatRewardsValue = if (fiatRate != null && cryptoRewardsValue != null) {
+ fiatRate.times(cryptoRewardsValue)
+ } else {
+ null
+ }
InnerYieldBalanceState.Data(
rewardsCrypto = BigDecimalFormatter.formatCryptoAmount(
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt
index 790ed90374..4b1bdd6992 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt
@@ -8,10 +8,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.staking.*
import com.tangem.domain.staking.model.PendingTransaction
import com.tangem.domain.staking.model.SubmitHashData
-import com.tangem.domain.staking.model.stakekit.BalanceType
-import com.tangem.domain.staking.model.stakekit.PendingAction
-import com.tangem.domain.staking.model.stakekit.StakingError
-import com.tangem.domain.staking.model.stakekit.Yield
+import com.tangem.domain.staking.model.stakekit.*
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
@@ -35,6 +32,7 @@ import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import timber.log.Timber
import java.math.BigDecimal
+import java.util.UUID
@Suppress("LongParameterList")
internal class StakingTransactionSender @AssistedInject constructor(
@@ -91,12 +89,16 @@ internal class StakingTransactionSender @AssistedInject constructor(
sendStakingTransaction(
fullTransactionsData = fullTransactionsData,
- balanceState = confirmationState.balanceState,
+ possiblePendingTransaction = composePendingTransaction(confirmationState),
onSendSuccess = onSendSuccess,
onSendError = onSendError,
)
}
+ private fun composePendingTransaction(confirmationState: StakingStates.ConfirmationState.Data): PendingTransaction {
+ return confirmationState.possiblePendingTransaction ?: composeStakeTransaction(confirmationState)
+ }
+
private suspend fun getStakingTransactions(
state: StakingUiState,
confirmationState: StakingStates.ConfirmationState.Data,
@@ -204,7 +206,7 @@ internal class StakingTransactionSender @AssistedInject constructor(
private suspend fun sendStakingTransaction(
fullTransactionsData: List,
- balanceState: BalanceState?,
+ possiblePendingTransaction: PendingTransaction,
onSendSuccess: (txUrl: String) -> Unit,
onSendError: (SendTransactionError?) -> Unit,
) {
@@ -218,13 +220,9 @@ internal class StakingTransactionSender @AssistedInject constructor(
},
ifRight = { transactionHashes ->
submitHash(
- transactionIds = fullTransactionsData.map { it.stakeKitTransaction.id },
+ transactions = fullTransactionsData.map { it.stakeKitTransaction },
transactionHashes = transactionHashes,
- groupId = balanceState?.groupId,
- validator = balanceState?.validator,
- amount = balanceState?.cryptoDecimal,
- balanceType = balanceState?.type,
- rawCurrencyId = balanceState?.rawCurrencyId,
+ pendingTransaction = possiblePendingTransaction,
)
val txUrl = getExplorerTransactionUrlUseCase(
txHash = transactionHashes.last(),
@@ -238,25 +236,18 @@ internal class StakingTransactionSender @AssistedInject constructor(
}
private suspend fun submitHash(
- transactionIds: List,
+ transactions: List,
transactionHashes: List,
- groupId: String?,
- validator: Yield.Validator?,
- amount: BigDecimal?,
- balanceType: BalanceType?,
- rawCurrencyId: String?,
+ pendingTransaction: PendingTransaction,
) {
- transactionIds
+ transactions
.zip(transactionHashes)
- .forEach { (transactionId, transactionHash) ->
+ .forEach { (transaction, transactionHash) ->
submitHashUseCase(
SubmitHashData(
- transactionId = transactionId,
+ transactionId = transaction.id,
transactionHash = transactionHash,
- validator = validator,
- amount = amount,
- balanceType = balanceType,
- rawCurrencyId = rawCurrencyId,
+ pendingTransaction = pendingTransaction,
),
)
.onLeft { error ->
@@ -267,20 +258,14 @@ internal class StakingTransactionSender @AssistedInject constructor(
),
)
saveUnsubmittedHashUseCase.invoke(
- transactionId = transactionId,
+ transactionId = transaction.id,
transactionHash = transactionHash,
)
}.onRight {
Timber.d("Successful hash submission")
- savePendingTransactionUseCase.invoke(
- PendingTransaction(
- groupId = groupId,
- type = balanceType,
- amount = amount,
- rawCurrencyId = rawCurrencyId,
- validator = validator,
- ),
- )
+ if (transaction.type != StakingTransactionType.FREEZE_ENERGY) {
+ savePendingTransactionUseCase.invoke(userWallet.walletId, pendingTransaction)
+ }
}
}
}
@@ -299,6 +284,19 @@ internal class StakingTransactionSender @AssistedInject constructor(
)
}
+ private fun composeStakeTransaction(confirmationState: StakingStates.ConfirmationState.Data): PendingTransaction {
+ val state = stateController.value
+
+ return PendingTransaction(
+ groupId = UUID.randomUUID().toString(),
+ type = BalanceType.STAKED,
+ amount = (state.amountState as? AmountState.Data)?.amountTextField?.cryptoAmount?.value ?: BigDecimal.ZERO,
+ rawCurrencyId = cryptoCurrencyStatus.currency.id.rawCurrencyId,
+ validator = (confirmationState.validatorState as? ValidatorState.Content)?.chosenValidator,
+ balancesId = (cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data)?.getBalancesUniqueId() ?: 0,
+ )
+ }
+
private data class FullTransactionData(
val stakeKitTransaction: StakingTransaction,
val tangemTransaction: TransactionData.Compiled,
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmationStatePreviewData.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmationStatePreviewData.kt
index 51b7ec69a2..d9c7263d8e 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmationStatePreviewData.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmationStatePreviewData.kt
@@ -28,6 +28,7 @@ internal object ConfirmationStatePreviewData {
website = "https://luganodes.com/",
votingPower = 0.09778360195377911,
preferred = true,
+ isStrategicPartner = false,
),
Yield.Validator(
address = "0x35b1ca0f398905cf752e6fe122b51c88022fca32",
@@ -40,6 +41,7 @@ internal object ConfirmationStatePreviewData {
website = "https://infstones.com/",
votingPower = 0.0034366257754399774,
preferred = true,
+ isStrategicPartner = false,
),
Yield.Validator(
address = "0xd14a87025109013b0a2354a775cb335f926af65a",
@@ -52,6 +54,7 @@ internal object ConfirmationStatePreviewData {
website = "https://infstones.com/",
votingPower = 0.023487238579718264,
preferred = true,
+ isStrategicPartner = true,
),
)
@@ -93,6 +96,6 @@ internal object ConfirmationStatePreviewData {
isApprovalNeeded = false,
reduceAmountBy = null,
pendingActions = null,
- balanceState = null,
+ possiblePendingTransaction = null,
)
}
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/InitialStakingStatePreview.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/InitialStakingStatePreview.kt
index e42df87aba..d3890582f5 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/InitialStakingStatePreview.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/InitialStakingStatePreview.kt
@@ -86,6 +86,7 @@ internal object InitialStakingStatePreview {
stakedBalance = null,
votingPower = null,
preferred = false,
+ isStrategicPartner = false,
),
pendingActions = persistentListOf(),
isClickable = true,
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/AddStakingNotificationsTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/AddStakingNotificationsTransformer.kt
index 8d5c155cf7..b482379c49 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/AddStakingNotificationsTransformer.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/AddStakingNotificationsTransformer.kt
@@ -255,30 +255,23 @@ internal class AddStakingNotificationsTransformer(
}
private fun MutableList.addExitInfoNotifications() {
- add(
- StakingNotification.Info.Unstake(
- cooldownPeriodDays = yield.metadata.cooldownPeriod.days,
- subtitleRes = if (isCosmos(cryptoCurrencyStatusProvider().currency.network.id.value)) {
- R.string.staking_notification_unstake_cosmos_text
- } else {
- R.string.staking_notification_unstake_text
- },
- ),
- )
+ val cooldownPeriodDays = yield.metadata.cooldownPeriod?.days
+ if (cooldownPeriodDays != null) {
+ add(
+ StakingNotification.Info.Unstake(
+ cooldownPeriodDays = cooldownPeriodDays,
+ subtitleRes = if (isCosmos(cryptoCurrencyStatusProvider().currency.network.id.value)) {
+ R.string.staking_notification_unstake_cosmos_text
+ } else {
+ R.string.staking_notification_unstake_text
+ },
+ ),
+ )
+ }
}
private fun MutableList.addEnterInfoNotifications() {
- val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
- val isTron = isTron(cryptoCurrencyStatus.currency.network.id.value)
- val hasStakedBalance = (cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data)?.balance
- ?.items?.any {
- it.type == BalanceType.PREPARING ||
- it.type == BalanceType.STAKED ||
- it.type == BalanceType.LOCKED
- } == true
- if (hasStakedBalance && isTron) {
- add(StakingNotification.Info.TronRevote)
- }
+ addTronRevoteNotification()
}
private fun MutableList.addPendingInfoNotifications(prevState: StakingUiState) {
@@ -298,28 +291,55 @@ internal class AddStakingNotificationsTransformer(
resourceReference(R.string.staking_notification_withdraw_text)
}
StakingActionType.UNLOCK_LOCKED -> {
- val cooldownPeriodDays = yield.metadata.cooldownPeriod.days
- resourceReference(R.string.staking_unlocked_locked) to resourceReference(
- R.string.staking_notification_unlock_text,
- wrappedList(
- pluralReference(
- id = R.plurals.common_days,
- count = cooldownPeriodDays,
- formatArgs = wrappedList(cooldownPeriodDays),
+ val cooldownPeriodDays = yield.metadata.cooldownPeriod?.days
+ if (cooldownPeriodDays != null) {
+ resourceReference(R.string.staking_unlocked_locked) to resourceReference(
+ R.string.staking_notification_unlock_text,
+ wrappedList(
+ pluralReference(
+ id = R.plurals.common_days,
+ count = cooldownPeriodDays,
+ formatArgs = wrappedList(cooldownPeriodDays),
+ ),
),
- ),
- )
+ )
+ } else {
+ null to null
+ }
+ }
+ StakingActionType.VOTE_LOCKED -> {
+ resourceReference(R.string.staking_revote) to
+ resourceReference(R.string.staking_notifications_revote_tron_text)
}
else -> null to null
}
if (titleReference != null && textReference != null) {
add(
- StakingNotification.Info.PendingAction(
+ StakingNotification.Info.Ordinary(
title = titleReference,
text = textReference,
),
)
}
}
+
+ private fun MutableList.addTronRevoteNotification() {
+ val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
+ val isTron = isTron(cryptoCurrencyStatus.currency.network.id.value)
+ val hasStakedBalance = (cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data)?.balance
+ ?.items?.any {
+ it.type == BalanceType.PREPARING ||
+ it.type == BalanceType.STAKED ||
+ it.type == BalanceType.LOCKED
+ } == true
+ if (isTron && hasStakedBalance) {
+ add(
+ StakingNotification.Info.Ordinary(
+ title = resourceReference(R.string.staking_revote),
+ text = resourceReference(R.string.staking_notifications_revote_tron_text),
+ ),
+ )
+ }
+ }
}
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetBalanceStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetBalanceStateTransformer.kt
deleted file mode 100644
index d6fae7cd7f..0000000000
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetBalanceStateTransformer.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.tangem.features.staking.impl.presentation.state.transformers
-
-import com.tangem.features.staking.impl.presentation.state.*
-import com.tangem.utils.transformer.Transformer
-
-internal class SetBalanceStateTransformer(
- private val balanceState: BalanceState? = null,
-) : Transformer {
-
- override fun transform(prevState: StakingUiState): StakingUiState {
- val possibleConfirmationState = prevState.confirmationState as? StakingStates.ConfirmationState.Data
- ?: return prevState
-
- return prevState.copy(
- confirmationState = possibleConfirmationState.copy(balanceState = balanceState),
- )
- }
-}
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetButtonsStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetButtonsStateTransformer.kt
index d9f2906670..ea4406d986 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetButtonsStateTransformer.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetButtonsStateTransformer.kt
@@ -144,9 +144,19 @@ internal class SetButtonsStateTransformer(
clickIntents.onAmountValueChange("") // reset amount state
clickIntents.onNextClick(StakingActionCommonType.ENTER)
}
- StakingStep.Validators,
- StakingStep.Amount,
- -> clickIntents.onNextClick()
+ StakingStep.Validators -> {
+ if (confirmationState is StakingStates.ConfirmationState.Data) {
+ clickIntents.onNextClick(
+ pendingActions = confirmationState.pendingActions,
+ pendingAction = confirmationState.pendingAction,
+ )
+ } else {
+ clickIntents.onNextClick()
+ }
+ }
+ StakingStep.Amount -> {
+ clickIntents.onNextClick()
+ }
StakingStep.Confirmation -> onConfirmationClick()
StakingStep.RewardsValidators -> Unit
}
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt
index c2df5db972..60e1fd090c 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt
@@ -20,9 +20,12 @@ internal class SetConfirmationStateLoadingTransformer(
) : Transformer {
override fun transform(prevState: StakingUiState): StakingUiState {
+ val filteredValidators = yield.validators.filter {
+ it.preferred
+ }
val possibleConfirmationState = prevState.confirmationState as? StakingStates.ConfirmationState.Data
val possibleValidatorState = possibleConfirmationState?.validatorState as? ValidatorState.Content
- val chosenValidator = possibleValidatorState?.chosenValidator ?: yield.validators[0]
+ val chosenValidator = possibleValidatorState?.chosenValidator ?: filteredValidators[0]
return prevState.copy(
confirmationState = StakingStates.ConfirmationState.Data(
@@ -32,7 +35,7 @@ internal class SetConfirmationStateLoadingTransformer(
validatorState = ValidatorState.Content(
isClickable = true,
chosenValidator = chosenValidator,
- availableValidators = yield.validators,
+ availableValidators = filteredValidators,
),
notifications = persistentListOf(),
footerText = getFooter(prevState, chosenValidator),
@@ -41,7 +44,7 @@ internal class SetConfirmationStateLoadingTransformer(
pendingActions = possibleConfirmationState?.pendingActions,
isApprovalNeeded = false,
reduceAmountBy = null,
- balanceState = null,
+ possiblePendingTransaction = null,
),
)
}
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateResetAssentTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateResetAssentTransformer.kt
index ee866db72c..a3b203d9eb 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateResetAssentTransformer.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateResetAssentTransformer.kt
@@ -3,6 +3,7 @@ package com.tangem.features.staking.impl.presentation.state.transformers
import com.tangem.features.staking.impl.presentation.state.InnerConfirmationStakingState
import com.tangem.features.staking.impl.presentation.state.StakingStates
import com.tangem.features.staking.impl.presentation.state.StakingUiState
+import com.tangem.features.staking.impl.presentation.state.ValidatorState
import com.tangem.utils.transformer.Transformer
internal object SetConfirmationStateResetAssentTransformer : Transformer {
@@ -13,7 +14,7 @@ internal object SetConfirmationStateResetAssentTransformer : Transformer {
+
+ override fun transform(prevState: StakingUiState): StakingUiState {
+ val possibleConfirmationState =
+ prevState.confirmationState as? StakingStates.ConfirmationState.Data ?: return prevState
+
+ val balancesId = (cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data)?.getBalancesUniqueId() ?: 0
+
+ return prevState.copy(
+ confirmationState = possibleConfirmationState.copy(
+ possiblePendingTransaction = PendingTransaction(
+ groupId = balanceState.groupId,
+ type = balanceState.type,
+ amount = balanceState.cryptoDecimal,
+ rawCurrencyId = balanceState.rawCurrencyId,
+ validator = balanceState.validator,
+ balancesId = balancesId,
+ ),
+ ),
+ )
+ }
+}
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt
index 8fc799719a..bcf6eb3cc3 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt
@@ -19,6 +19,7 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
+import com.tangem.domain.staking.model.stakekit.action.StakingActionType
import com.tangem.features.staking.impl.R
import com.tangem.features.staking.impl.presentation.state.InnerConfirmationStakingState
import com.tangem.features.staking.impl.presentation.state.StakingStates
@@ -39,6 +40,7 @@ internal fun StakingConfirmationContent(
) {
if (state !is StakingStates.ConfirmationState.Data) return
val isEnterAction = type == StakingActionCommonType.ENTER
+ val showValidatorBlock = isEnterAction || state.pendingAction?.type == StakingActionType.VOTE_LOCKED
val isTransactionSent = state.innerState == InnerConfirmationStakingState.COMPLETED
Column(
modifier = Modifier
@@ -63,7 +65,7 @@ internal fun StakingConfirmationContent(
isEditingDisabled = !isEnterAction && state.innerState != InnerConfirmationStakingState.COMPLETED,
onClick = clickIntents::onPrevClick,
)
- if (isEnterAction) {
+ if (showValidatorBlock) {
ValidatorBlock(validatorState = state.validatorState, onClick = clickIntents::openValidators)
}
StakingFeeBlock(feeState = state.feeState, isTransactionSent = isTransactionSent)
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt
index c86ebb7e95..9ddda86f32 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt
@@ -5,16 +5,22 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.inputrow.InputRowImageSelector
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
import com.tangem.core.ui.extensions.*
@@ -78,6 +84,9 @@ internal fun StakingValidatorListContent(
false,
)
.background(TangemTheme.colors.background.action),
+ subtitleExtraContent = {
+ ValidatorLabel(item.isStrategicPartner)
+ },
selectorContent = { checked, _, _ ->
AnimatedVisibility(
modifier = Modifier,
@@ -99,6 +108,23 @@ internal fun StakingValidatorListContent(
}
}
+@Composable
+private fun RowScope.ValidatorLabel(isStrategicPartner: Boolean) {
+ if (isStrategicPartner) {
+ Text(
+ text = stringResource(R.string.staking_validators_label),
+ style = TangemTheme.typography.caption1,
+ color = TangemTheme.colors.icon.constant,
+ modifier = Modifier
+ .align(Alignment.CenterVertically)
+ .padding(horizontal = 6.dp)
+ .clip(RoundedCornerShape(6.dp))
+ .background(TangemTheme.colors.text.accent)
+ .padding(horizontal = 8.dp),
+ )
+ }
+}
+
// region Preview
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt
index 662e4e6828..4e21b0746c 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt
@@ -133,9 +133,12 @@ internal class StakingViewModel @Inject constructor(
private val balancesToShow: List
get() {
- return cryptoCurrencyStatus.value.yieldBalance?.let {
- invalidatePendingTransactionsUseCase(it).getOrElse { emptyList() }
- } ?: emptyList()
+ val yieldBalance = cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data
+ return invalidatePendingTransactionsUseCase(
+ userWalletId = userWallet.walletId,
+ balanceItems = yieldBalance?.balance?.items ?: emptyList(),
+ balancesId = yieldBalance?.getBalancesUniqueId() ?: 0,
+ ).getOrElse { emptyList() }
}
private var isInitialInfoAnalyticSent: Boolean = false
@@ -215,13 +218,31 @@ internal class StakingViewModel @Inject constructor(
stakingStateRouter.onNextClick()
when {
isInitState() -> {
+ stateController.update(SetConfirmationStateResetAssentTransformer)
stateController.update(SetConfirmationStateLoadingTransformer(yield, appCurrency))
- stateController.update(SetBalanceStateTransformer(balanceState))
+ if (balanceState != null) {
+ stateController.update(SetPossiblePendingTransactionTransformer(balanceState, cryptoCurrencyStatus))
+ }
+
+ stateController.update(
+ transformer = SetInitialDataStateTransformer(
+ clickIntents = this@StakingViewModel,
+ yield = yield,
+ isAnyTokenStaked = true,
+ isApprovalNeeded = stakingApproval is StakingApproval.Needed,
+ cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
+ userWalletProvider = Provider { userWallet },
+ appCurrencyProvider = Provider { appCurrency },
+ balancesToShowProvider = Provider { balancesToShow },
+ ),
+ )
onRefreshSwipe(isRefreshing = false)
}
isAssentState() -> {
getFee(pendingAction, pendingActions)
- stateController.update(SetBalanceStateTransformer(balanceState))
+ if (balanceState != null) {
+ stateController.update(SetPossiblePendingTransactionTransformer(balanceState, cryptoCurrencyStatus))
+ }
val amountState = value.amountState as? AmountState.Data
if (amountState?.amountTextField?.isWarning == true) {
stateController.update(
@@ -325,6 +346,7 @@ internal class StakingViewModel @Inject constructor(
if (value.currentStep == StakingStep.Confirmation) {
when ((value.confirmationState as? StakingStates.ConfirmationState.Data)?.innerState) {
InnerConfirmationStakingState.ASSENT -> {
+ stateController.update(SetConfirmationStateResetAssentTransformer)
stakingStateRouter.onPrevClick()
}
null,
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt
index 24a7b170f3..4ddc9c283e 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt
@@ -14,6 +14,7 @@ import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.model.StakingEntryInfo
+import com.tangem.domain.staking.model.stakekit.BalanceItem
import com.tangem.domain.staking.model.stakekit.RewardBlockType
import com.tangem.domain.staking.model.stakekit.YieldBalance
import com.tangem.domain.tokens.error.CurrencyStatusError
@@ -38,6 +39,7 @@ internal class TokenDetailsLoadedBalanceConverter(
private val currentStateProvider: Provider,
private val appCurrencyProvider: Provider,
private val stakingEntryInfoProvider: Provider,
+ private val pendingBalancesProvider: Provider>,
private val stakingAvailabilityProvider: Provider,
private val symbol: String,
private val decimals: Int,
@@ -145,6 +147,8 @@ internal class TokenDetailsLoadedBalanceConverter(
val stakingEntryInfo = stakingEntryInfoProvider.invoke()
val stakingAvailability = stakingAvailabilityProvider.invoke()
val iconState = state.tokenInfoBlockState.iconState
+ val pendingBalances = pendingBalancesProvider.invoke()
+ val fiatRate = status.value.fiatRate
return when {
stakingAvailability == StakingAvailability.TemporaryUnavailable -> {
@@ -153,14 +157,24 @@ internal class TokenDetailsLoadedBalanceConverter(
stakingAvailability == StakingAvailability.Unavailable -> {
null
}
- stakingCryptoAmount.isNullOrZero() && stakingEntryInfo != null -> {
+ stakingCryptoAmount.isNullOrZero() && stakingEntryInfo != null && pendingBalances.isEmpty() -> {
getStakeAvailableState(stakingEntryInfo, iconState)
}
+ stakingCryptoAmount.isNullOrZero() && stakingEntryInfo != null && pendingBalances.isNotEmpty() -> {
+ val pendingBalancesCryptoAmount = pendingBalances.sumOf { it.amount }
+
+ val stakingFiatAmount = fiatRate?.multiply(pendingBalancesCryptoAmount)
+ getStakedState(
+ status = status,
+ stakingCryptoAmount = pendingBalancesCryptoAmount,
+ stakingFiatAmount = stakingFiatAmount,
+ stakingRewardAmount = null,
+ )
+ }
stakingCryptoAmount.isNullOrZero() && stakingEntryInfo == null -> {
null
}
else -> {
- val fiatRate = status.value.fiatRate
val stakingRewardAmount = yieldBalance?.getRewardStakingBalance()?.let { fiatRate?.multiply(it) }
val stakingFiatAmount = stakingCryptoAmount?.let { fiatRate?.multiply(it) }
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt
index c3bc29d4a4..cfb9d29ed4 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt
@@ -20,6 +20,7 @@ import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.staking.GetStakingIntegrationIdUseCase
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.model.StakingEntryInfo
+import com.tangem.domain.staking.model.stakekit.BalanceItem
import com.tangem.domain.tokens.error.CurrencyStatusError
import com.tangem.domain.tokens.model.*
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
@@ -52,6 +53,7 @@ internal class TokenDetailsStateFactory(
private val stakingEntryInfoProvider: Provider,
private val stakingAvailabilityProvider: Provider,
private val cryptoCurrencyStatusProvider: Provider,
+ private val pendingBalancesProvider: Provider>,
private val clickIntents: TokenDetailsClickIntents,
private val networkHasDerivationUseCase: NetworkHasDerivationUseCase,
private val getUserWalletUseCase: GetUserWalletUseCase,
@@ -82,6 +84,7 @@ internal class TokenDetailsStateFactory(
appCurrencyProvider = appCurrencyProvider,
stakingEntryInfoProvider = stakingEntryInfoProvider,
stakingAvailabilityProvider = stakingAvailabilityProvider,
+ pendingBalancesProvider = pendingBalancesProvider,
symbol = symbol,
decimals = decimals,
clickIntents = clickIntents,
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt
index d85c3693a2..d3a0fa897a 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt
@@ -32,12 +32,14 @@ import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.settings.ShouldShowSwapPromoTokenUseCase
+import com.tangem.domain.staking.GetStakingPendingTransactionsUseCase
import com.tangem.domain.staking.GetStakingAvailabilityUseCase
import com.tangem.domain.staking.GetStakingEntryInfoUseCase
import com.tangem.domain.staking.GetStakingIntegrationIdUseCase
import com.tangem.domain.staking.GetYieldUseCase
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.model.StakingEntryInfo
+import com.tangem.domain.staking.model.stakekit.BalanceItem
import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.legacy.TradeCryptoAction.TransactionInfo
@@ -119,6 +121,7 @@ internal class TokenDetailsViewModel @Inject constructor(
private val swapTransactionStatusStore: SwapTransactionStatusStore,
private val isDemoCardUseCase: IsDemoCardUseCase,
private val associateAssetUseCase: AssociateAssetUseCase,
+ private val getStakingPendingTransactionsUseCase: GetStakingPendingTransactionsUseCase,
private val reduxStateHolder: ReduxStateHolder,
private val analyticsEventsHandler: AnalyticsEventHandler,
private val vibratorHapticManager: VibratorHapticManager,
@@ -148,6 +151,8 @@ internal class TokenDetailsViewModel @Inject constructor(
private val warningsJobHolder = JobHolder()
private val swapTxJobHolder = JobHolder()
private val selectedAppCurrencyFlow: StateFlow = createSelectedAppCurrencyFlow()
+ private val stakingPendingBalances: List
+ get() = getStakingPendingTransactionsUseCase(userWalletId).getOrElse { emptyList() }
private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null
private var stakingEntryInfo: StakingEntryInfo? = null
@@ -160,6 +165,7 @@ internal class TokenDetailsViewModel @Inject constructor(
stakingEntryInfoProvider = Provider { stakingEntryInfo },
stakingAvailabilityProvider = Provider { stakingAvailability },
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
+ pendingBalancesProvider = Provider { stakingPendingBalances },
clickIntents = this,
networkHasDerivationUseCase = networkHasDerivationUseCase,
getUserWalletUseCase = getUserWalletUseCase,
diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml
index 7e9f817bae..ba4ad15a6f 100644
--- a/gradle/dependencies.toml
+++ b/gradle/dependencies.toml
@@ -89,11 +89,11 @@ markdownComposeView = "0.5.4"
# endregion Other libraries
# region Tangem
-tangemBlockchainSdk = "develop-805"
+tangemBlockchainSdk = "develop-811"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
-tangemCardSdk = "develop-385"
+tangemCardSdk = "develop-387"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
-tangemVico = "2.0.0-alpha.25-tangem16"
+tangemVico = "2.0.0-alpha.25-tangem17"
#tangemVico = "0.0.1" # Keep it! - used for local builds ^
# endregion Tangem
diff --git a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/utils/Blockchain.kt b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/utils/Blockchain.kt
index 6bc59c27af..239018b6a9 100644
--- a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/utils/Blockchain.kt
+++ b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/utils/Blockchain.kt
@@ -126,10 +126,14 @@ fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain? {
"sei-network" -> Blockchain.Sei
"sei-network/test" -> Blockchain.SeiTestnet
"internet-computer" -> Blockchain.InternetComputer
+ "sui" -> Blockchain.Sui
+ "sui/test" -> Blockchain.SuiTestnet
"energy-web-chain" -> Blockchain.EnergyWebChain
"energy-web-chain/test" -> Blockchain.EnergyWebChainTestnet
"energy-web-x" -> Blockchain.EnergyWebX
"energy-web-x/test" -> Blockchain.EnergyWebXTestnet
+ "add_later" -> Blockchain.Casper
+ "add_later_test" -> Blockchain.CasperTestnet
else -> null
}
}
@@ -257,10 +261,14 @@ fun Blockchain.toNetworkId(): String {
Blockchain.Sei -> "sei-network"
Blockchain.SeiTestnet -> "sei-network/test"
Blockchain.InternetComputer -> "internet-computer"
+ Blockchain.Sui -> "sui"
+ Blockchain.SuiTestnet -> "sui/test"
Blockchain.EnergyWebChain -> "energy-web-chain"
Blockchain.EnergyWebChainTestnet -> "energy-web-chain/test"
Blockchain.EnergyWebX -> "energy-web-x"
Blockchain.EnergyWebXTestnet -> "energy-web-x/test"
+ Blockchain.Casper -> "add_later"
+ Blockchain.CasperTestnet -> "add_later_test"
}
}
@@ -345,8 +353,11 @@ fun Blockchain.toCoinId(): String {
Blockchain.Cyber, Blockchain.CyberTestnet -> "cyber-ethereum"
Blockchain.Sei, Blockchain.SeiTestnet -> "sei-network"
Blockchain.InternetComputer -> "internet-computer"
+ Blockchain.Sui, Blockchain.SuiTestnet -> "sui"
Blockchain.EnergyWebChain, Blockchain.EnergyWebChainTestnet -> "energy-web-token"
Blockchain.EnergyWebX, Blockchain.EnergyWebXTestnet -> "energy-web-token"
+ Blockchain.Casper -> "add_later"
+ Blockchain.CasperTestnet -> "add_later_test"
}
}
@@ -377,6 +388,5 @@ private const val NODL_AMOUNT_TO_CREATE_ACCOUNT = 1.5
private val excludedBlockchains = listOf(
Blockchain.Unknown,
Blockchain.Nexa,
- Blockchain.Sei,
- Blockchain.InternetComputer,
+ Blockchain.NexaTestnet,
)
\ No newline at end of file