Updated on 2026-08-14
This commit is contained in:
commit
1706a25d1a
61 changed files with 717 additions and 347 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 5b70b3652d06811e3f1292e41e735e00fe75783f
|
||||
Subproject commit d52c8382e9e94b2b44ceecd7cb7bd897e091073c
|
||||
|
|
@ -152,8 +152,8 @@ internal object StakingDomainModule {
|
|||
fun provideGetPendingTransactionsUseCase(
|
||||
stakingPendingTransactionRepository: StakingPendingTransactionRepository,
|
||||
stakingErrorResolver: StakingErrorResolver,
|
||||
): GetPendingTransactionsUseCase {
|
||||
return GetPendingTransactionsUseCase(
|
||||
): GetStakingPendingTransactionsUseCase {
|
||||
return GetStakingPendingTransactionsUseCase(
|
||||
stakingPendingTransactionRepository = stakingPendingTransactionRepository,
|
||||
stakingErrorResolver = stakingErrorResolver,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@
|
|||
<string name="common_no_address">Keine Adresse</string>
|
||||
<string name="common_now">Jetzt</string>
|
||||
<string name="common_ok">OK</string>
|
||||
<string name="common_origin_card">Primär Karte</string>
|
||||
<string name="common_origin_card">Hauptkarte</string>
|
||||
<string name="common_passphrase">Passphrase</string>
|
||||
<string name="common_paste">Einfügen</string>
|
||||
<string name="common_privacy_policy">Datenschutzbestimmungen</string>
|
||||
|
|
@ -275,7 +275,7 @@
|
|||
<string name="express_token_list_empty_search">Keine Token gefunden. Bitte versuche eine andere Anfrage</string>
|
||||
<string name="express_transaction_id">ID: %s</string>
|
||||
<string name="express_transaction_id_copied">Transaktions-ID kopiert</string>
|
||||
<string name="exсhange_token_description">Wechsel eine Ihrer Währungen in eine andere</string>
|
||||
<string name="exсhange_token_description">Tauschen jeden Vermögenswert in Deinem Portfolio gegen diesen Token</string>
|
||||
<string name="feedback_data_collection_message">Die folgenden Angaben sind freiwillig. Du kannst diese löschen, wenn du sie nicht weitergeben möchtest.</string>
|
||||
<string name="feedback_preface_rate_negative">Teile uns mit, welche Funktionen du vermisst, und wir werden versuchen, dir zu helfen.</string>
|
||||
<string name="feedback_preface_scan_failed">Bitte sag uns, welche Karte du hast</string>
|
||||
|
|
@ -345,6 +345,7 @@
|
|||
<string name="manage_tokens_wallet_support_only_one_network_title">Das Wallet unterstützt nicht mehr als ein Netzwerk</string>
|
||||
<string name="markets_add_to_my_portfolio_description">Um mit dem Kauf, Tausch oder Erhalt dieses Vermögenswerts zu beginnen, füge diesen Token zu mindestens 1 Netzwerk hinzu</string>
|
||||
<string name="markets_add_to_my_portfolio_unavailable_description">Dieses Asset ist nicht verfügbar</string>
|
||||
<string name="markets_add_to_my_portfolio_unavailable_for_wallet_description">Dieses Asset ist für dieses Wallet nicht verfügbar</string>
|
||||
<string name="markets_add_to_portfolio_button">Zum Portfolio hinzufügen</string>
|
||||
<string name="markets_add_token">Hinzufügen</string>
|
||||
<string name="markets_available_networks">Verfügbare Netzwerke</string>
|
||||
|
|
@ -561,7 +562,7 @@
|
|||
<item quantity="one">%d Wallet</item>
|
||||
<item quantity="other">%d Wallets</item>
|
||||
</plurals>
|
||||
<string name="reset_card_to_factory_button_title">Zurücksetzen der Karte</string>
|
||||
<string name="reset_card_to_factory_button_title">Karte zurücksetzen</string>
|
||||
<string name="reset_card_to_factory_condition_1">Mir ist bewusst, dass ich nach der Durchführung dieser Aktion keinen Zugriff mehr auf die aktuelle Wallet habe.</string>
|
||||
<string name="reset_card_to_factory_condition_2">Mir ist klar, dass ich diese Karte nicht verwenden kann, um meinen Zugangscode auf den anderen Karten der aktuellen Wallet wiederherzustellen</string>
|
||||
<string name="reset_card_with_backup_to_factory_message">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.</string>
|
||||
|
|
@ -686,7 +687,7 @@
|
|||
<string name="staking_details_unbonding_period_info">Der Zeitraum, den du nach der Beantragung der Abhebung von Geldern aus dem Staking warten musst, bevor die Token verfügbar werden.</string>
|
||||
<string name="staking_details_warmup_period">Aufwärmphase</string>
|
||||
<string name="staking_details_warmup_period_info">Die zugewiesene Zeit für die Aktivierung der Teilnahme am Staking.</string>
|
||||
<string name="staking_legal">Indem Du die Staking-Funktionalität nutzen, stimmst Du den %1$s und %2$s des Anbieters zu.</string>
|
||||
<string name="staking_legal">Indem Du die Staking-Funktionalität nutzt, stimmst Du den %1$s und %2$s des Anbieters zu.</string>
|
||||
<string name="staking_locked">Gesperrt</string>
|
||||
<string name="staking_migrate">Migrieren</string>
|
||||
<string name="staking_native">Natives Staking</string>
|
||||
|
|
@ -718,14 +719,15 @@
|
|||
<string name="staking_revote">Neuwahl</string>
|
||||
<string name="staking_reward_claiming_auto">Automatisch</string>
|
||||
<string name="staking_reward_claiming_manual">Händisch</string>
|
||||
<string name="staking_reward_schedule_block">Block</string>
|
||||
<string name="staking_reward_schedule_day">Tag</string>
|
||||
<string name="staking_reward_schedule_block">Pro Block</string>
|
||||
<string name="staking_reward_schedule_day">Täglich</string>
|
||||
<string name="staking_reward_schedule_each_day">Täglich</string>
|
||||
<string name="staking_reward_schedule_epoch">Epoche</string>
|
||||
<string name="staking_reward_schedule_era">Ära</string>
|
||||
<string name="staking_reward_schedule_hour">Stunde</string>
|
||||
<string name="staking_reward_schedule_month">Monat</string>
|
||||
<string name="staking_reward_schedule_week">Woche</string>
|
||||
<string name="staking_reward_schedule_each_sec">Alle %1$s Sek.</string>
|
||||
<string name="staking_reward_schedule_epoch">Pro Epoche</string>
|
||||
<string name="staking_reward_schedule_era">Pro Ära</string>
|
||||
<string name="staking_reward_schedule_hour">Stündlich</string>
|
||||
<string name="staking_reward_schedule_month">Monatlich</string>
|
||||
<string name="staking_reward_schedule_week">Wöchentlich</string>
|
||||
<string name="staking_rewards">Belohnungen</string>
|
||||
<string name="staking_stake_locked">Stake gesperrt</string>
|
||||
<string name="staking_stake_more">Mehr staken</string>
|
||||
|
|
@ -743,6 +745,7 @@
|
|||
<string name="staking_unstaking_item_name">Unstake Assets %s</string>
|
||||
<string name="staking_validator">Validator/ Prüfer</string>
|
||||
<string name="staking_validators">Validatoren</string>
|
||||
<string name="staking_validators_label">Strategischer Partner</string>
|
||||
<string name="staking_vote">Abstimmung</string>
|
||||
<string name="staking_vote_locked">Abstimmung gesperrt</string>
|
||||
<string name="staking_withdraw">Zurückziehen</string>
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@
|
|||
</plurals>
|
||||
<string name="manage_tokens_remove">Eliminar</string>
|
||||
<string name="manage_tokens_search_placeholder">por ejemplo, BTC I trust, hodl I must</string>
|
||||
<string name="manage_tokens_toast_portfolio_updated">Su cartera ha sido actualizada</string>
|
||||
<string name="manage_tokens_toast_portfolio_updated">Su portafolio ha sido actualizada</string>
|
||||
<string name="manage_tokens_unavailable_description">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.</string>
|
||||
<string name="manage_tokens_unavailable_vote">Votar a favor</string>
|
||||
<string name="manage_tokens_wallet_selector_title">Elegir wallet</string>
|
||||
|
|
@ -373,7 +373,7 @@
|
|||
<string name="markets_sort_by_experienced_buyers_title">Compradores experimentados</string>
|
||||
<string name="markets_sort_by_rating_title">Evaluación</string>
|
||||
<string name="markets_sort_by_title">Ordenar por</string>
|
||||
<string name="markets_sort_by_top_gainers_title">Mejores Ganadores</string>
|
||||
<string name="markets_sort_by_top_gainers_title">Top Ganadores</string>
|
||||
<string name="markets_sort_by_top_losers_title">Top Perdedores</string>
|
||||
<string name="markets_sort_by_trending_title">Tendencias</string>
|
||||
<string name="markets_token_details_about_token_title">Acerca de %s</string>
|
||||
|
|
@ -720,6 +720,7 @@
|
|||
<string name="staking_reward_schedule_block">Bloquear</string>
|
||||
<string name="staking_reward_schedule_day">Día</string>
|
||||
<string name="staking_reward_schedule_each_day">Cada día</string>
|
||||
<string name="staking_reward_schedule_each_sec">Cada %1$s segundo(s)</string>
|
||||
<string name="staking_reward_schedule_epoch">Época</string>
|
||||
<string name="staking_reward_schedule_era">Era</string>
|
||||
<string name="staking_reward_schedule_hour">Hora</string>
|
||||
|
|
@ -742,8 +743,9 @@
|
|||
<string name="staking_unstaking_item_name">Detenando el staking de activos %s</string>
|
||||
<string name="staking_validator">Validador</string>
|
||||
<string name="staking_validators">Validadores</string>
|
||||
<string name="staking_validators_label">Socio estratégico</string>
|
||||
<string name="staking_vote">Votar</string>
|
||||
<string name="staking_vote_locked">Voto bloqueado</string>
|
||||
<string name="staking_vote_locked">Votar</string>
|
||||
<string name="staking_withdraw">Retirar</string>
|
||||
<string name="staking_your_stakes">Sus stakes</string>
|
||||
<string name="story_awe_description">Almacene sus activos crypto de forma segura manteniendo las claves privadas contenidas en su tarjeta</string>
|
||||
|
|
|
|||
|
|
@ -720,6 +720,7 @@
|
|||
<string name="staking_reward_schedule_block">Bloquer</string>
|
||||
<string name="staking_reward_schedule_day">Jour</string>
|
||||
<string name="staking_reward_schedule_each_day">Chaque jour</string>
|
||||
<string name="staking_reward_schedule_each_sec">Toute(s) les %1$s seconde(s)</string>
|
||||
<string name="staking_reward_schedule_epoch">Époque</string>
|
||||
<string name="staking_reward_schedule_era">Ère</string>
|
||||
<string name="staking_reward_schedule_hour">Heure</string>
|
||||
|
|
@ -742,8 +743,9 @@
|
|||
<string name="staking_unstaking_item_name">En train de destaker les actifs %s</string>
|
||||
<string name="staking_validator">Validateur</string>
|
||||
<string name="staking_validators">Validateurs</string>
|
||||
<string name="staking_validators_label">Partenaire stratégique</string>
|
||||
<string name="staking_vote">Voter</string>
|
||||
<string name="staking_vote_locked">Vote bloqué</string>
|
||||
<string name="staking_vote_locked">Voter</string>
|
||||
<string name="staking_withdraw">Retirer</string>
|
||||
<string name="staking_your_stakes">Vos stakes</string>
|
||||
<string name="story_awe_description">Stockez vos actifs crypto en toute sécurité tout en conservant les clés privées contenues dans votre carte</string>
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@
|
|||
<plurals name="common_days">
|
||||
<item quantity="other">%d 日</item>
|
||||
</plurals>
|
||||
<plurals name="common_days_no_param">
|
||||
<item quantity="other">日</item>
|
||||
</plurals>
|
||||
<string name="common_delete">削除</string>
|
||||
<string name="common_disabled">無効</string>
|
||||
<string name="common_done">完了</string>
|
||||
|
|
@ -340,8 +343,9 @@
|
|||
<string name="manage_tokens_unavailable_vote">賛成票を投じる</string>
|
||||
<string name="manage_tokens_wallet_selector_title">ウォレットを選択</string>
|
||||
<string name="manage_tokens_wallet_support_only_one_network_title">ウォレットは複数のネットワークをサポートしていません。</string>
|
||||
<string name="markets_add_to_my_portfolio_description">このアセットの購入、交換、受け取りを開始するには、ポートフォリオに追加してください。</string>
|
||||
<string name="markets_add_to_my_portfolio_description">このアセットを購入・交換・受け取るには、ポートフォリオに追加してください。</string>
|
||||
<string name="markets_add_to_my_portfolio_unavailable_description">このアセットは利用できません</string>
|
||||
<string name="markets_add_to_my_portfolio_unavailable_for_wallet_description">このアセットはこのウォレットでは使用できません。</string>
|
||||
<string name="markets_add_to_portfolio_button">ポートフォリオに追加</string>
|
||||
<string name="markets_add_token">追加</string>
|
||||
<string name="markets_available_networks">利用可能なネットワーク</string>
|
||||
|
|
@ -388,6 +392,11 @@
|
|||
<string name="markets_token_details_circulating_supply_description">取引可能で市場に流通しているコインの総数</string>
|
||||
<string name="markets_token_details_circulating_supply_full">循環供給量</string>
|
||||
<string name="markets_token_details_empty_exchanges">取引所が見つかりません</string>
|
||||
<string name="markets_token_details_exchange">取引所</string>
|
||||
<string name="markets_token_details_exchange_trust_score_caution">注意</string>
|
||||
<string name="markets_token_details_exchange_trust_score_risky">危険</string>
|
||||
<string name="markets_token_details_exchange_trust_score_trusted">信頼できる</string>
|
||||
<string name="markets_token_details_exchanges_title">取引所</string>
|
||||
<string name="markets_token_details_experienced_buyers">経験豊富な買い手</string>
|
||||
<string name="markets_token_details_experienced_buyers_description">少なくとも100の発信取引を持つネット・バイヤー</string>
|
||||
<string name="markets_token_details_experienced_buyers_full">経験豊富な買い手</string>
|
||||
|
|
@ -428,6 +437,7 @@
|
|||
<string name="markets_token_details_trading_volume">取引量(24時間)</string>
|
||||
<string name="markets_token_details_trading_volume_24h_description">過去24時間以内に取引された暗号資産の合計額。市場の活発さと流動性を示します。</string>
|
||||
<string name="markets_token_details_trading_volume_full">取引量(24時間)</string>
|
||||
<string name="markets_token_details_volume">取引量</string>
|
||||
<string name="markets_tooltip_message">これをドラッグするか、検索窓をタップして、マーケットから直接トークンを追加します</string>
|
||||
<string name="markets_tooltip_title">トークンを追加</string>
|
||||
<string name="nfc_error_unavailable">お使いのデバイスではNFCが使用できません</string>
|
||||
|
|
@ -716,7 +726,10 @@
|
|||
<string name="staking_reward_claiming_manual">手動</string>
|
||||
<string name="staking_reward_schedule_block">ブロック毎</string>
|
||||
<string name="staking_reward_schedule_day">毎日</string>
|
||||
<string name="staking_reward_schedule_each">%sごと</string>
|
||||
<string name="staking_reward_schedule_each_day">毎日</string>
|
||||
<string name="staking_reward_schedule_each_days">%1$s日ごとに</string>
|
||||
<string name="staking_reward_schedule_each_sec">%1$s秒毎</string>
|
||||
<string name="staking_reward_schedule_epoch">エポック毎</string>
|
||||
<string name="staking_reward_schedule_era">時代毎</string>
|
||||
<string name="staking_reward_schedule_hour">毎時間</string>
|
||||
|
|
@ -727,6 +740,7 @@
|
|||
<string name="staking_stake_more">もっとステーキングする</string>
|
||||
<string name="staking_summary_description_text">%1$sをステーキングし、年間 %2$sを受け取ります</string>
|
||||
<string name="staking_tap_to_unlock">タップしてロック解除</string>
|
||||
<string name="staking_tap_to_unlock_or_vote">タップしてロック解除もしくは投票</string>
|
||||
<string name="staking_tap_to_withdraw">タップして引き出す</string>
|
||||
<string name="staking_title_stake">%sをステーキングする</string>
|
||||
<string name="staking_title_unstake">%sのステーキング解除</string>
|
||||
|
|
@ -739,8 +753,9 @@
|
|||
<string name="staking_unstaking_item_name">ステーキング解除中の資産%s</string>
|
||||
<string name="staking_validator">バリデーター</string>
|
||||
<string name="staking_validators">バリデーター</string>
|
||||
<string name="staking_validators_label">戦略的パートナー</string>
|
||||
<string name="staking_vote">投票する</string>
|
||||
<string name="staking_vote_locked">投票はロックされています</string>
|
||||
<string name="staking_vote_locked">投票する</string>
|
||||
<string name="staking_withdraw">引き出す</string>
|
||||
<string name="staking_your_stakes">あなたのステーキング</string>
|
||||
<string name="story_awe_description">カード内に秘密鍵を保管しながら暗号資産を安全に保管します</string>
|
||||
|
|
@ -804,6 +819,7 @@
|
|||
<string name="transaction_history_operation">オペレーション</string>
|
||||
<string name="transaction_history_transaction_from_address">送金元: %s</string>
|
||||
<string name="transaction_history_transaction_to_address">送金先: %s</string>
|
||||
<string name="transaction_history_transaction_validator">バリデーター: %s</string>
|
||||
<string name="try_to_load_data_again_button_title">もう一度やり直してください</string>
|
||||
<string name="twin_error_same_card">同じカードをスキャンしました。ツインウォレットを作成するには、番号%dのカードをスキャンする必要があります。</string>
|
||||
<string name="twin_error_wrong_twin">間違ったツインカードをスキャンしました。別のカードをお試しください。</string>
|
||||
|
|
|
|||
|
|
@ -101,6 +101,12 @@
|
|||
<item quantity="many">%d дней</item>
|
||||
<item quantity="other">%d дней</item>
|
||||
</plurals>
|
||||
<plurals name="common_days_no_param">
|
||||
<item quantity="one">день</item>
|
||||
<item quantity="few">дня</item>
|
||||
<item quantity="many">дней</item>
|
||||
<item quantity="other">дней</item>
|
||||
</plurals>
|
||||
<string name="common_delete">Удалить</string>
|
||||
<string name="common_disabled">Отключено</string>
|
||||
<string name="common_done">Готово</string>
|
||||
|
|
@ -403,6 +409,9 @@
|
|||
<string name="markets_token_details_circulating_supply_full">Циркулирующее предложение</string>
|
||||
<string name="markets_token_details_empty_exchanges">Биржи не найдены</string>
|
||||
<string name="markets_token_details_exchange">Биржа</string>
|
||||
<string name="markets_token_details_exchange_trust_score_caution">Осторожно</string>
|
||||
<string name="markets_token_details_exchange_trust_score_risky">Рискованно</string>
|
||||
<string name="markets_token_details_exchange_trust_score_trusted">Надежно</string>
|
||||
<string name="markets_token_details_exchanges_title">Биржи</string>
|
||||
<string name="markets_token_details_experienced_buyers">Опытные трейдеры</string>
|
||||
<string name="markets_token_details_experienced_buyers_description">Покупатели, у которых было как минимум 100 исходящих транзакций.</string>
|
||||
|
|
@ -445,7 +454,7 @@
|
|||
<string name="markets_token_details_trading_volume_24h_description">Общая сумма криптовалюты, которая была продана за последние 24 часа, показывающая уровень активности и ликвидности на рынке.</string>
|
||||
<string name="markets_token_details_trading_volume_full">Объем торгов (24ч)</string>
|
||||
<string name="markets_token_details_volume">Объем</string>
|
||||
<string name="markets_tooltip_message">Потяните вверх или коснитесь поисковой строки, чтобы добавить токены напрямую из маркета</string>
|
||||
<string name="markets_tooltip_message">Потяните вверх или коснитесь поисковой строки, чтобы добавить токены напрямую из рынка</string>
|
||||
<string name="markets_tooltip_title">Добавить токены</string>
|
||||
<string name="nfc_error_unavailable">Функция NFC недоступна на вашем устройстве</string>
|
||||
<string name="onboarding_access_code_feature_1_description">Вам необходимо установить единый код доступа для защиты всех ваших карт</string>
|
||||
|
|
@ -520,7 +529,7 @@
|
|||
<string name="onboarding_subtitle_scan_primary_card_format">Подготовьте основную карту с номером %s</string>
|
||||
<string name="onboarding_subtitle_success_tangem_wallet_onboarding">Ваша карта настроена и готова к использованию.</string>
|
||||
<string name="onboarding_subtitle_two_backup_cards">Добавлено максимальное количество карт. Завершите процесс резервного копирования.</string>
|
||||
<string name="onboarding_title">Активация карты</string>
|
||||
<string name="onboarding_title">Активация кошелька</string>
|
||||
<string name="onboarding_title_backup_card_format">Резервная карта #%d</string>
|
||||
<string name="onboarding_title_no_backup_cards">Нет резервных карт</string>
|
||||
<string name="onboarding_title_notifications">Уведомления</string>
|
||||
|
|
@ -745,6 +754,8 @@
|
|||
<string name="staking_reward_schedule_block">За блок</string>
|
||||
<string name="staking_reward_schedule_day">Ежедневно</string>
|
||||
<string name="staking_reward_schedule_each_day">Каждый день</string>
|
||||
<string name="staking_reward_schedule_each_days">Каждые %1$s дня</string>
|
||||
<string name="staking_reward_schedule_each_sec">Каждые %1$s сек</string>
|
||||
<string name="staking_reward_schedule_epoch">За эпоху</string>
|
||||
<string name="staking_reward_schedule_era">За эру</string>
|
||||
<string name="staking_reward_schedule_hour">Ежечасно</string>
|
||||
|
|
@ -755,6 +766,7 @@
|
|||
<string name="staking_stake_more">Застейкать еще</string>
|
||||
<string name="staking_summary_description_text">Вы стейкаете %1$s и будете получать %2$s ежегодно</string>
|
||||
<string name="staking_tap_to_unlock">Нажмите для разблокировки</string>
|
||||
<string name="staking_tap_to_unlock_or_vote">Нажмите для разблокировки или голосования</string>
|
||||
<string name="staking_tap_to_withdraw">Нажмите для вывода</string>
|
||||
<string name="staking_title_stake">Застейкать %s</string>
|
||||
<string name="staking_title_unstake">Вывести %s</string>
|
||||
|
|
@ -767,8 +779,9 @@
|
|||
<string name="staking_unstaking_item_name">Завершение стейкинга %s</string>
|
||||
<string name="staking_validator">Валидатор</string>
|
||||
<string name="staking_validators">Валидаторы</string>
|
||||
<string name="staking_validators_label">Стратегический партнер</string>
|
||||
<string name="staking_vote">Проголосовать</string>
|
||||
<string name="staking_vote_locked">Голосование заблокировано</string>
|
||||
<string name="staking_vote_locked">Проголосовать</string>
|
||||
<string name="staking_withdraw">Вывод</string>
|
||||
<string name="staking_your_stakes">Застейканные средства</string>
|
||||
<string name="story_awe_description">Держите свои криптосбережения в безопасности. Приватные ключи надежно хранятся на карте.</string>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
<string name="common_read_more">Детальніше</string>
|
||||
<string name="common_receive">Отримати</string>
|
||||
<string name="common_reject">Відхилити</string>
|
||||
<string name="common_reload">Перезавантажити</string>
|
||||
<string name="common_reload">Оновити</string>
|
||||
<string name="common_rename">Перейменувати</string>
|
||||
<string name="common_save">Зберегти</string>
|
||||
<string name="common_save_changes">Зберегти зміни</string>
|
||||
|
|
@ -351,6 +351,7 @@
|
|||
<string name="manage_tokens_wallet_support_only_one_network_title">Гаманець не підтримує більше однієї мережі</string>
|
||||
<string name="markets_add_to_my_portfolio_description">Щоб почати купувати, обмінювати або отримувати цей актив, додайте цей токен принаймні в 1 мережу</string>
|
||||
<string name="markets_add_to_my_portfolio_unavailable_description">Цей актив недоступний</string>
|
||||
<string name="markets_add_to_my_portfolio_unavailable_for_wallet_description">Цей токен недоступний для цього гаманця</string>
|
||||
<string name="markets_add_to_portfolio_button">Додати в портфоліо</string>
|
||||
<string name="markets_add_token">Додати</string>
|
||||
<string name="markets_available_networks">Доступні мережі</string>
|
||||
|
|
@ -401,6 +402,7 @@
|
|||
<string name="markets_token_details_experienced_buyers_full">Досвідчені покупці</string>
|
||||
<string name="markets_token_details_fully_diluted_valuation">Повн. розведена кап.</string>
|
||||
<string name="markets_token_details_fully_diluted_valuation_description">Загальна теоретична вартість криптовалюти, якщо всі монети, які могли б існувати, перебувають в обігу, включаючи ті, що не перебувають в обігу в даний час</string>
|
||||
<string name="markets_token_details_fully_diluted_valuation_full">Повністю розведена капіталізація</string>
|
||||
<string name="markets_token_details_genesis_date">Дата створення</string>
|
||||
<string name="markets_token_details_high">Високий</string>
|
||||
<string name="markets_token_details_holders">Тримачі</string>
|
||||
|
|
@ -415,9 +417,11 @@
|
|||
<string name="markets_token_details_low">Низький</string>
|
||||
<string name="markets_token_details_market_capitalization">Рин. кап.</string>
|
||||
<string name="markets_token_details_market_capitalization_description">Загальна ринкова вартість криптовалюти, що розраховується шляхом множення поточної ціни монети на загальну кількість монет в обігу</string>
|
||||
<string name="markets_token_details_market_capitalization_full">Ринкова капіталізація</string>
|
||||
<string name="markets_token_details_market_rating">Рейтинг</string>
|
||||
<string name="markets_token_details_market_rating_description">Позиція в крипторейтингу між усіма монетами на основі ринкової капіталізації</string>
|
||||
<string name="markets_token_details_market_rating_full">Рейтинг</string>
|
||||
<string name="markets_token_details_max_supply">Макс. обсяг</string>
|
||||
<string name="markets_token_details_max_supply_description">Максимальна кількість монет або токенів, яка може коли-небудь існувати для певної криптовалюти</string>
|
||||
<string name="markets_token_details_max_supply_full">Максимальна пропозиція</string>
|
||||
<string name="markets_token_details_metrics">Метрики</string>
|
||||
|
|
@ -713,6 +717,7 @@
|
|||
<string name="staking_notification_earn_rewards_text_period_week">Стейкінг дозволяє заробляти %1$s. Ваші винагороди за стейкінг зараховуються щотиждня.</string>
|
||||
<string name="staking_notification_earn_rewards_text_weekly">Стейкайте безпечно та почніть отримувати винагороди щотижня</string>
|
||||
<string name="staking_notification_earn_rewards_title">Отримуйте винагороду за стейкінг</string>
|
||||
<string name="staking_notification_network_error_text">Стейкінг тимчасово недоступний через проблеми в мережі. Будь ласка, спробуйте пізніше.</string>
|
||||
<string name="staking_notification_new_validator_funds_transfer">Стейкінг в мережі %1$s з новим валідатором автоматично переведе всі раніше застейкані кошти до цього валідатора</string>
|
||||
<string name="staking_notification_restake_rewards_text">Реінвестуйте зароблені винагороди у суму стейкінгу, щоб збільшити потенційний прибуток.</string>
|
||||
<string name="staking_notification_unlock_text">Розблокуйте свої кошти, щоб вивести їх зі стейкінгу. Розблокування займе %s.</string>
|
||||
|
|
@ -732,6 +737,7 @@
|
|||
<string name="staking_reward_schedule_block">Блок</string>
|
||||
<string name="staking_reward_schedule_day">День</string>
|
||||
<string name="staking_reward_schedule_each_day">Щодня</string>
|
||||
<string name="staking_reward_schedule_each_sec">Кожні %1$s сек</string>
|
||||
<string name="staking_reward_schedule_epoch">Епоха</string>
|
||||
<string name="staking_reward_schedule_era">Ера</string>
|
||||
<string name="staking_reward_schedule_hour">Година</string>
|
||||
|
|
@ -754,6 +760,7 @@
|
|||
<string name="staking_unstaking_item_name">Виведення зі стейкінгу %s</string>
|
||||
<string name="staking_validator">Валідатор</string>
|
||||
<string name="staking_validators">Валідатори</string>
|
||||
<string name="staking_validators_label">Стратегічний партнер</string>
|
||||
<string name="staking_vote">Проголосувати</string>
|
||||
<string name="staking_vote_locked">Голос заблоковано</string>
|
||||
<string name="staking_withdraw">Зняти</string>
|
||||
|
|
@ -813,12 +820,13 @@
|
|||
<string name="token_swap_promotion_button">Обміняти</string>
|
||||
<string name="transaction_history_contract_address">контракт: %s</string>
|
||||
<string name="transaction_history_empty_transactions">У вас ще немає транзакцій</string>
|
||||
<string name="transaction_history_error_failed_to_load">Не вдалося завантажити історію транзакцій.\nНатисніть кнопку перезавантаження, щоб оновити інформацію.</string>
|
||||
<string name="transaction_history_error_failed_to_load">Не вдалося завантажити історію транзакцій.\nНатисніть кнопку нижче, щоб оновити інформацію</string>
|
||||
<string name="transaction_history_multiple_addresses">Кілька адрес</string>
|
||||
<string name="transaction_history_not_supported_description">Історія транзакцій наразі не підтримується для цього блокчейну. Але не хвилюйтеся, ми працюємо над цим! А поки можете перевірити це в оглядачі.</string>
|
||||
<string name="transaction_history_operation">Операція</string>
|
||||
<string name="transaction_history_transaction_from_address">від: %s</string>
|
||||
<string name="transaction_history_transaction_to_address">до: %s</string>
|
||||
<string name="transaction_history_transaction_validator">валідатор: %s</string>
|
||||
<string name="try_to_load_data_again_button_title">Спробуйте знову</string>
|
||||
<string name="twin_error_same_card">Ви відсканували одну й ту саму картку. Для створення twin-гаманця вам потрібно відсканувати картку з номером %d</string>
|
||||
<string name="twin_error_wrong_twin">Ви відсканували не ту twin-картку. Будь ласка, спробуйте відсканувати іншу</string>
|
||||
|
|
|
|||
|
|
@ -97,6 +97,10 @@
|
|||
<item quantity="one">%d day</item>
|
||||
<item quantity="other">%d days</item>
|
||||
</plurals>
|
||||
<plurals name="common_days_no_param">
|
||||
<item quantity="one">day</item>
|
||||
<item quantity="other">days</item>
|
||||
</plurals>
|
||||
<string name="common_delete">Delete</string>
|
||||
<string name="common_disabled">Disabled</string>
|
||||
<string name="common_done">Done</string>
|
||||
|
|
@ -128,7 +132,7 @@
|
|||
<string name="common_no_address">No address</string>
|
||||
<string name="common_now">Now</string>
|
||||
<string name="common_ok">OK</string>
|
||||
<string name="common_origin_card">Primary Card</string>
|
||||
<string name="common_origin_card">Primary card</string>
|
||||
<string name="common_passphrase">Passphrase</string>
|
||||
<string name="common_paste">Paste</string>
|
||||
<string name="common_privacy_policy">Privacy Policy</string>
|
||||
|
|
@ -511,7 +515,7 @@
|
|||
<string name="onboarding_subtitle_scan_primary_card_format">Prepare the primary card with number %s</string>
|
||||
<string name="onboarding_subtitle_success_tangem_wallet_onboarding">Your wallet card is configured and ready for use.</string>
|
||||
<string name="onboarding_subtitle_two_backup_cards">Max number of cards added. Finalize the backup process.</string>
|
||||
<string name="onboarding_title">Activating card</string>
|
||||
<string name="onboarding_title">Activating wallet</string>
|
||||
<string name="onboarding_title_backup_card_format">Backup card #%d</string>
|
||||
<string name="onboarding_title_no_backup_cards">No backup cards</string>
|
||||
<string name="onboarding_title_notifications">Notifications</string>
|
||||
|
|
@ -573,7 +577,7 @@
|
|||
<item quantity="one">%d wallet</item>
|
||||
<item quantity="other">%d wallets</item>
|
||||
</plurals>
|
||||
<string name="reset_card_to_factory_button_title">Reset the Card</string>
|
||||
<string name="reset_card_to_factory_button_title">Reset the card</string>
|
||||
<string name="reset_card_to_factory_condition_1">I understand that after performing this action, I will no longer have access to the current wallet</string>
|
||||
<string name="reset_card_to_factory_condition_2">I realize that I can\'t use this card to recover my access code on the other cards of the current wallet</string>
|
||||
<string name="reset_card_with_backup_to_factory_message">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.</string>
|
||||
|
|
@ -589,7 +593,7 @@
|
|||
<string name="save_user_wallet_agreement_enroll_biometrics_title">Enable biometric authorization</string>
|
||||
<string name="save_user_wallet_agreement_header_biometrics">Would you like to use biometrics?</string>
|
||||
<string name="save_user_wallet_agreement_notice">Note that making a transaction with your funds will still require your card</string>
|
||||
<string name="scan_card_settings_button">Scan Card</string>
|
||||
<string name="scan_card_settings_button">Scan card</string>
|
||||
<string name="scan_card_settings_message">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.</string>
|
||||
<string name="scan_card_settings_title">Get your card ready!</string>
|
||||
<string name="send_additional_field_already_included">Already included in the entered address</string>
|
||||
|
|
@ -691,7 +695,7 @@
|
|||
<string name="staking_details_reward_claiming">Reward claiming</string>
|
||||
<string name="staking_details_reward_claiming_info">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.</string>
|
||||
<string name="staking_details_reward_schedule">Reward schedule</string>
|
||||
<string name="staking_details_reward_schedule_info">This is a schedule that determines when participants in staking receive their rewards.</string>
|
||||
<string name="staking_details_reward_schedule_info">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.</string>
|
||||
<string name="staking_details_rewards_to_claim">Rewards: %s</string>
|
||||
<string name="staking_details_title">Staking %s</string>
|
||||
<string name="staking_details_unbonding_period">Unbonding Period</string>
|
||||
|
|
@ -732,7 +736,10 @@
|
|||
<string name="staking_reward_claiming_manual">Manual</string>
|
||||
<string name="staking_reward_schedule_block">Per Block</string>
|
||||
<string name="staking_reward_schedule_day">Daily</string>
|
||||
<string name="staking_reward_schedule_each_day">Daily</string>
|
||||
<string name="staking_reward_schedule_each">Each %s</string>
|
||||
<string name="staking_reward_schedule_each_day">Each day</string>
|
||||
<string name="staking_reward_schedule_each_days">Each %1$s days</string>
|
||||
<string name="staking_reward_schedule_each_sec">Each %1$s sec</string>
|
||||
<string name="staking_reward_schedule_epoch">Per Epoch</string>
|
||||
<string name="staking_reward_schedule_era">Per Era</string>
|
||||
<string name="staking_reward_schedule_hour">Hourly</string>
|
||||
|
|
@ -743,6 +750,7 @@
|
|||
<string name="staking_stake_more">Stake more</string>
|
||||
<string name="staking_summary_description_text">You stake %1$s and will be receiving %2$s yearly</string>
|
||||
<string name="staking_tap_to_unlock">Tap to unlock</string>
|
||||
<string name="staking_tap_to_unlock_or_vote">Tap to unlock or vote</string>
|
||||
<string name="staking_tap_to_withdraw">Tap to withdraw</string>
|
||||
<string name="staking_title_stake">Stake %s</string>
|
||||
<string name="staking_title_unstake">Unstake %s</string>
|
||||
|
|
@ -755,8 +763,9 @@
|
|||
<string name="staking_unstaking_item_name">Unstaking assets %s</string>
|
||||
<string name="staking_validator">Validator</string>
|
||||
<string name="staking_validators">Validators</string>
|
||||
<string name="staking_validators_label">Strategic partner</string>
|
||||
<string name="staking_vote">Vote</string>
|
||||
<string name="staking_vote_locked">Vote locked</string>
|
||||
<string name="staking_vote_locked">Vote</string>
|
||||
<string name="staking_withdraw">Withdraw</string>
|
||||
<string name="staking_your_stakes">Your stakes</string>
|
||||
<string name="story_awe_description">Store your crypto assets secure while keeping private keys contained in your card</string>
|
||||
|
|
@ -843,7 +852,7 @@
|
|||
<string name="user_wallet_list_error_wallet_already_saved">This wallet has already been saved, you can add another one</string>
|
||||
<string name="user_wallet_list_rename_popup_error_already_exists">The wallet with name %s already exists</string>
|
||||
<string name="user_wallet_list_rename_popup_placeholder">Wallet name</string>
|
||||
<string name="user_wallet_list_rename_popup_title">Rename Wallet</string>
|
||||
<string name="user_wallet_list_rename_popup_title">Rename wallet</string>
|
||||
<string name="user_wallet_list_unlock_all">Unlock all</string>
|
||||
<string name="user_wallet_list_unlock_all_with">Unlock all with %s</string>
|
||||
<string name="wallet_balance_blockchain_unreachable_try_later">Blockchain is unreachable. Try later</string>
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
9
core/ui/src/main/res/drawable/ic_sui_22.xml
Normal file
9
core/ui/src/main/res/drawable/ic_sui_22.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
<path
|
||||
android:pathData="M14.8,9.7C15.4,10.5 15.8,11.5 15.8,12.7C15.8,13.8 15.4,14.9 14.7,15.7L14.7,15.8L14.7,15.7C14.6,15.6 14.6,15.5 14.6,15.4C14.3,14 13.2,12.7 11.4,11.7C10.2,11 9.5,10.1 9.3,9.2C9.2,8.6 9.3,8 9.4,7.5C9.6,6.9 9.9,6.5 10.1,6.2L10.8,5.4C10.9,5.2 11.1,5.2 11.2,5.4L14.8,9.7H14.8ZM15.9,8.8L11.2,3.1C11.1,3 10.9,3 10.8,3.1L6.1,8.8L6.1,8.8C5.3,9.9 4.8,11.3 4.8,12.8C4.8,16.2 7.6,19 11,19C14.5,19 17.3,16.2 17.3,12.8C17.3,11.3 16.7,9.9 15.9,8.8L15.9,8.8L15.9,8.8ZM7.3,9.7L7.7,9.1L7.7,9.2C7.7,9.3 7.7,9.4 7.7,9.5C8,10.9 9,12.1 10.6,13C12,13.8 12.8,14.7 13.1,15.7C13.2,16.2 13.2,16.6 13.1,16.9L13.1,17L13.1,17C12.5,17.3 11.8,17.5 11,17.5C8.4,17.5 6.2,15.3 6.2,12.7C6.2,11.5 6.6,10.5 7.3,9.7L7.3,9.7Z"
|
||||
android:fillColor="#000" />
|
||||
</vector>
|
||||
15
core/ui/src/main/res/drawable/img_sui_22.xml
Normal file
15
core/ui/src/main/res/drawable/img_sui_22.xml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
<clip-path
|
||||
android:pathData="M11,0L11,0A11,11 0,0 1,22 11L22,11A11,11 0,0 1,11 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z"/>
|
||||
|
||||
<path
|
||||
android:pathData="M0,0h22v22h-22z"
|
||||
android:fillColor="#4CA3FF"/>
|
||||
<path
|
||||
android:pathData="M14.8,9.7C15.4,10.5 15.8,11.5 15.8,12.7C15.8,13.8 15.4,14.9 14.7,15.7L14.7,15.8L14.7,15.7C14.6,15.6 14.6,15.5 14.6,15.4C14.3,14 13.2,12.7 11.4,11.7C10.2,11 9.5,10.1 9.3,9.2C9.2,8.6 9.3,8 9.4,7.5C9.6,6.9 9.9,6.5 10.1,6.2L10.8,5.4C10.9,5.2 11.1,5.2 11.2,5.4L14.8,9.7H14.8ZM15.9,8.8L11.2,3.1C11.1,3 10.9,3 10.8,3.1L6.1,8.8L6.1,8.8C5.3,9.9 4.8,11.3 4.8,12.8C4.8,16.2 7.6,19 11,19C14.5,19 17.3,16.2 17.3,12.8C17.3,11.3 16.7,9.9 15.9,8.8L15.9,8.8L15.9,8.8ZM7.3,9.7L7.7,9.1L7.7,9.2C7.7,9.3 7.7,9.4 7.7,9.5C8,10.9 9,12.1 10.6,13C12,13.8 12.8,14.7 13.1,15.7C13.2,16.2 13.2,16.6 13.1,16.9L13.1,17L13.1,17C12.5,17.3 11.8,17.5 11,17.5C8.4,17.5 6.2,15.3 6.2,12.7C6.2,11.5 6.6,10.5 7.3,9.7L7.3,9.7Z"
|
||||
android:fillColor="#ffffff" />
|
||||
</vector>
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<ManageTokensListConfig, List<ManagedCryptoCurrency>> = 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<ManageTokensListConfig>,
|
||||
isFirstBatchFetching: Boolean,
|
||||
): BatchFetchResult.Success<List<ManagedCryptoCurrency>> {
|
||||
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<ManageTokensListConfig>,
|
||||
): BatchFetchResult.Success<List<ManagedCryptoCurrency>> {
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ManagedCryptoCurrency> {
|
||||
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<ManagedCryptoCurrency> {
|
||||
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<ManagedCryptoCurrency> = 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"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<PendingTransaction>()
|
||||
private val pendingTransactionsMap = ConcurrentHashMap<UserWalletId, CopyOnWriteArrayList<PendingTransaction>>()
|
||||
|
||||
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<PendingTransaction>) {
|
||||
pendingTransactions.removeAll(transactions)
|
||||
override fun removeTransactions(userWalletId: UserWalletId, transactions: Set<PendingTransaction>) {
|
||||
pendingTransactionsMap[userWalletId]?.removeAll(transactions)
|
||||
}
|
||||
|
||||
override fun getTransactionsWithBalanceItems(): List<Pair<PendingTransaction, BalanceItem>> {
|
||||
return pendingTransactions.mapNotNull { pendingTransaction ->
|
||||
override fun getTransactionsWithBalanceItems(
|
||||
userWalletId: UserWalletId,
|
||||
): List<Pair<PendingTransaction, BalanceItem>> {
|
||||
return pendingTransactionsMap[userWalletId]?.mapNotNull { pendingTransaction: PendingTransaction ->
|
||||
PendingTransactionItemConverter.convert(pendingTransaction)?.let { balanceItem ->
|
||||
pendingTransaction to balanceItem
|
||||
}
|
||||
}
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
|
@ -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<UserWalletId, Boolean>(),
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ internal object PendingTransactionItemConverter : Converter<PendingTransaction,
|
|||
override fun convert(value: PendingTransaction): BalanceItem? {
|
||||
return BalanceItem(
|
||||
groupId = value.groupId ?: return null,
|
||||
type = value.type ?: return null,
|
||||
amount = value.amount ?: return null,
|
||||
type = value.type,
|
||||
amount = value.amount,
|
||||
rawCurrencyId = value.rawCurrencyId,
|
||||
validatorAddress = value.validator?.address,
|
||||
date = DateTime.now(),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.tangem.data.staking.converters
|
|||
import com.tangem.data.staking.converters.action.PendingActionConverter
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.domain.staking.model.stakekit.*
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionType
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class YieldBalanceConverter : Converter<YieldBalanceWrapperDTO, YieldBalance> {
|
||||
|
|
@ -27,9 +26,7 @@ internal class YieldBalanceConverter : Converter<YieldBalanceWrapperDTO, YieldBa
|
|||
validatorAddress = item.validatorAddress ?: item.validatorAddresses?.get(0),
|
||||
date = item.date?.toDateTime(),
|
||||
pendingActions = pendingActionConverter
|
||||
.convertList(item.pendingActions)
|
||||
// temporarily exclude VOTE_LOCKED, it will be implemented in future iterations
|
||||
.filterNot { it.type == StakingActionType.VOTE_LOCKED },
|
||||
.convertList(item.pendingActions),
|
||||
isPending = false,
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,18 +4,16 @@ import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrap
|
|||
import com.tangem.domain.staking.model.stakekit.YieldBalanceList
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class YieldBalanceListConverter : Converter<Set<YieldBalanceWrapperDTO>, YieldBalanceList> {
|
||||
|
||||
internal val converter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
YieldBalanceConverter()
|
||||
}
|
||||
internal class YieldBalanceListConverter(
|
||||
private val yieldBalanceConverter: YieldBalanceConverter,
|
||||
) : Converter<Set<YieldBalanceWrapperDTO>, YieldBalanceList> {
|
||||
|
||||
override fun convert(value: Set<YieldBalanceWrapperDTO>): YieldBalanceList {
|
||||
return if (value.isEmpty()) {
|
||||
YieldBalanceList.Empty
|
||||
} else {
|
||||
YieldBalanceList.Data(
|
||||
balances = value.map(converter::convert),
|
||||
balances = value.map(yieldBalanceConverter::convert),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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<Token>,
|
||||
val type: String,
|
||||
val rewardSchedule: RewardSchedule,
|
||||
val cooldownPeriod: Period,
|
||||
val cooldownPeriod: Period?,
|
||||
val warmupPeriod: Period,
|
||||
val rewardClaiming: RewardClaiming,
|
||||
val defaultValidator: String?,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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<StakingError, List<BalanceItem>> {
|
||||
operator fun invoke(userWalletId: UserWalletId): Either<StakingError, List<BalanceItem>> {
|
||||
return Either.catch {
|
||||
stakingPendingTransactionRepository.getTransactionsWithBalanceItems().map { it.second }
|
||||
stakingPendingTransactionRepository.getTransactionsWithBalanceItems(userWalletId).map { it.second }
|
||||
}.mapLeft {
|
||||
stakingErrorResolver.resolve(it)
|
||||
}
|
||||
|
|
@ -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<StakingError, List<BalanceItem>> {
|
||||
operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
balanceItems: List<BalanceItem>,
|
||||
balancesId: Int,
|
||||
): Either<StakingError, List<BalanceItem>> {
|
||||
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<BalanceItem>,
|
||||
pending: List<Pair<PendingTransaction, BalanceItem>>,
|
||||
realData: List<BalanceItem>,
|
||||
newBalancesId: Int,
|
||||
pendingData: List<Pair<PendingTransaction, BalanceItem>>,
|
||||
): Pair<List<BalanceItem>, List<PendingTransaction>> {
|
||||
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<PendingTransaction>()
|
||||
val transactionsToRemove = mutableListOf<PendingTransaction>()
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -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<StakingError, Unit> {
|
||||
operator fun invoke(userWalletId: UserWalletId, transaction: PendingTransaction): Either<StakingError, Unit> {
|
||||
return Either.catch {
|
||||
stakingPendingTransactionRepository.saveTransaction(pendingTransaction)
|
||||
stakingPendingTransactionRepository.saveTransaction(
|
||||
userWalletId = userWalletId,
|
||||
transaction = transaction,
|
||||
)
|
||||
}.mapLeft {
|
||||
stakingErrorResolver.resolve(it)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Pair<PendingTransaction, BalanceItem>>
|
||||
fun getTransactionsWithBalanceItems(userWalletId: UserWalletId): List<Pair<PendingTransaction, BalanceItem>>
|
||||
|
||||
fun saveTransaction(transaction: PendingTransaction)
|
||||
fun saveTransaction(userWalletId: UserWalletId, transaction: PendingTransaction)
|
||||
|
||||
fun removeTransactions(transactions: Set<PendingTransaction>)
|
||||
fun removeTransactions(userWalletId: UserWalletId, transactions: Set<PendingTransaction>)
|
||||
}
|
||||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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<FullTransactionData>,
|
||||
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<String>,
|
||||
transactions: List<StakingTransaction>,
|
||||
transactionHashes: List<String>,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
@ -86,6 +86,7 @@ internal object InitialStakingStatePreview {
|
|||
stakedBalance = null,
|
||||
votingPower = null,
|
||||
preferred = false,
|
||||
isStrategicPartner = false,
|
||||
),
|
||||
pendingActions = persistentListOf(),
|
||||
isClickable = true,
|
||||
|
|
|
|||
|
|
@ -255,30 +255,23 @@ internal class AddStakingNotificationsTransformer(
|
|||
}
|
||||
|
||||
private fun MutableList<NotificationUM>.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<NotificationUM>.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<NotificationUM>.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<NotificationUM>.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),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
val possibleConfirmationState = prevState.confirmationState as? StakingStates.ConfirmationState.Data
|
||||
?: return prevState
|
||||
|
||||
return prevState.copy(
|
||||
confirmationState = possibleConfirmationState.copy(balanceState = balanceState),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,12 @@ internal class SetConfirmationStateLoadingTransformer(
|
|||
) : Transformer<StakingUiState> {
|
||||
|
||||
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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<StakingUiState> {
|
||||
|
|
@ -13,7 +14,7 @@ internal object SetConfirmationStateResetAssentTransformer : Transformer<Staking
|
|||
confirmationState.copy(
|
||||
isPrimaryButtonEnabled = true,
|
||||
innerState = InnerConfirmationStakingState.ASSENT,
|
||||
validatorState = confirmationState.validatorState.copySealed(isClickable = true),
|
||||
validatorState = ValidatorState.Loading,
|
||||
)
|
||||
} else {
|
||||
confirmationState
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ internal class SetInitialDataStateTransformer(
|
|||
return listOfNotNull(
|
||||
createAnnualPercentageRateItem(yield.validators),
|
||||
createAvailableItem(cryptoCurrencyStatus),
|
||||
createUnbondingPeriodItem(yield.metadata.cooldownPeriod.days),
|
||||
createUnbondingPeriodItem(yield.metadata.cooldownPeriod?.days),
|
||||
createMinimumRequirementItem(
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
minimumCryptoAmount = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]?.minimum,
|
||||
|
|
@ -140,7 +140,8 @@ internal class SetInitialDataStateTransformer(
|
|||
)
|
||||
}
|
||||
|
||||
private fun createUnbondingPeriodItem(cooldownPeriodDays: Int): RoundedListWithDividersItemData {
|
||||
private fun createUnbondingPeriodItem(cooldownPeriodDays: Int?): RoundedListWithDividersItemData? {
|
||||
cooldownPeriodDays ?: return null
|
||||
return RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_unbonding_period,
|
||||
startText = TextReference.Res(R.string.staking_details_unbonding_period),
|
||||
|
|
@ -231,7 +232,7 @@ internal class SetInitialDataStateTransformer(
|
|||
pendingActions = null,
|
||||
isApprovalNeeded = isApprovalNeeded,
|
||||
reduceAmountBy = null,
|
||||
balanceState = null,
|
||||
possiblePendingTransaction = null,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers
|
||||
|
||||
import com.tangem.domain.staking.model.PendingTransaction
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.staking.impl.presentation.state.*
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class SetPossiblePendingTransactionTransformer(
|
||||
private val balanceState: BalanceState,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
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,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -133,9 +133,12 @@ internal class StakingViewModel @Inject constructor(
|
|||
|
||||
private val balancesToShow: List<BalanceItem>
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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<TokenDetailsState>,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val stakingEntryInfoProvider: Provider<StakingEntryInfo?>,
|
||||
private val pendingBalancesProvider: Provider<List<BalanceItem>>,
|
||||
private val stakingAvailabilityProvider: Provider<StakingAvailability>,
|
||||
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) }
|
||||
|
||||
|
|
|
|||
|
|
@ -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<StakingEntryInfo?>,
|
||||
private val stakingAvailabilityProvider: Provider<StakingAvailability>,
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
private val pendingBalancesProvider: Provider<List<BalanceItem>>,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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<AppCurrency> = createSelectedAppCurrencyFlow()
|
||||
private val stakingPendingBalances: List<BalanceItem>
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue