From ba4e916cd08a2ccdadc1adeb6fb4299b99b36c97 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sat, 17 Jan 2026 15:15:04 +0300 Subject: [PATCH] Updated on 2026-08-14 --- core/res/src/main/res/values-es/strings.xml | 2 +- core/res/src/main/res/values-fr/strings.xml | 2 +- core/res/src/main/res/values-ja/strings.xml | 21 ++++++++++++++----- core/res/src/main/res/values-ru/strings.xml | 16 +++++++++++--- .../src/main/res/values-uk-rUA/strings.xml | 2 +- core/res/src/main/res/values/strings.xml | 7 +++++-- .../DefaultGaslessTransactionRepository.kt | 19 +++++++++++++++++ .../MockedGaslessTransactionRepository.kt | 4 ++++ data/wallet-manager/build.gradle.kts | 1 + .../DefaultWalletManagersFacade.kt | 3 +++ .../SdkTransactionHistoryItemConverter.kt | 2 ++ .../utils/SdkTransactionTypeConverter.kt | 18 ++++++++++++++++ .../src/main/assets/contract_methods.json | 5 +++++ .../tangem/domain/models/network/TxInfo.kt | 3 +++ .../GaslessTransactionRepository.kt | 2 ++ ...xHistoryItemToTransactionStateConverter.kt | 2 ++ .../converter/TxHistoryItemStateConverter.kt | 2 ++ 17 files changed, 98 insertions(+), 13 deletions(-) diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index fdd6015419..e80c01ac3c 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -1767,7 +1767,7 @@ Importa una billetera existente con su frase de recuperación. Importar billetera Introduzca la frase de recuperación - La copia de seguridad de su billetera se realizó con éxito. + Su billetera se ha importado con éxito. Importar billetera Importación completada Importar billetera diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 58a8d7eb70..ed570724fa 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -1753,7 +1753,7 @@ Importez un portefeuille existant à l\'aide de votre seedphrase. Importer un wallet Entrez la seedphrase - Vous avez sauvegardé votre portefeuille avec succès. + Vous avez importé votre portefeuille avec succès. Importer un wallet Importation terminée Importer un portefeuille diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 0dbce5c791..6ac1337a55 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -317,6 +317,7 @@ いいえ アドレスがありません 未追加 + 利用できません 今はしない わかりました @@ -531,6 +532,10 @@ ID: %s 取引IDをコピーしました ポートフォリオ内のアセットをこのトークンと交換する + 速度を上げるほど承認は速くなりますが、\nネットワーク手数料も高くなります。%s + 速度を選択 + \nネットワーク手数料の支払いに使用するトークンを選択します。%s + トークンを選択 マーケット&ニュース Tangem AI いま話題 @@ -588,7 +593,7 @@ 新しいウォレットを作成 Tangemの高性能ハードウェアウォレットで、セキュリティをさらに強化しましょう。 ハードウェアウォレット - 現在のウォレットをTangemに移します。 + 現在のモバイルウォレットをTangemのコールドウォレットに変換します。 現在のウォレットをアップグレードする バックアップへ移動 アクセスコードを作成する前にウォレットをバックアップしてください。 @@ -613,7 +618,7 @@ 本当にこれを実行しますか? ウォレット削除 バックアップへ移動 - バックアップを表示 + リカバリーフレーズを表示 ウォレット削除 とにかく削除する このウォレットにはバックアップがあります。ウォレットを削除する前に、復元できることを確認してください。 @@ -804,7 +809,7 @@ クイックまとめ 関連ニュース 関連トークン - 情報源 + 関連ニュース 最新情報を入手 お使いのデバイスではNFCが使用できません NFTについて @@ -1239,6 +1244,7 @@ APR APY 報酬は毎日自動的にステーキング残高に蓄積されます。 + 報酬はステーキング残高に自動的に複利で加算されます。獲得した資金:%s 利用可能 平均報酬率 ステーキングの仕組み @@ -1491,10 +1497,15 @@ KYC手続きを中止しますか?いつでも再開できます。 プロフィールを確認できませんでした。ご不明な点があればサポートまでお問い合わせください。 申し訳ございませんが、本人確認を行うことができませんでした + KYCの認証に失敗しました KYC進行中 ステータスを表示 Tangem PayのKYC手続き進行中 以下のボタンから、現在のKYCステータスを確認するか、KYCをキャンセルできます。 + KYCが承認されませんでした + KYCブロックを非表示 + 申し訳ありません、確認できませんでした + あなたのプロフィール。 無料のTangem Visaバーチャルカードを入手 日常の支払いにUSDCを利用 カードをGET @@ -1698,7 +1709,7 @@ リカバリーフレーズを使って既存のウォレットをインポートします。 ウォレットをインポート リカバリーフレーズを入力 - ウォレットのバックアップが正常に完了しました。 + ウォレットのインポートに成功しました。 ウォレットをインポート インポート完了 ウォレットをインポート @@ -1713,7 +1724,7 @@ このアクセスコードはウォレットを保護し、ログインや取引の署名に使用されます。 アクセスコードの設定・変更 アクセスコードを変更する - ウォレットの受信取引とTangemの更新について通知を受け取る。 + ウォレットへの入金取引をプッシュ通知で受け取る。 現在、Huaweiデバイスではプッシュ通知が機能しない可能性があります。現在、解決策の検討に取り組んでおり、今後のアップデートで修正をリリースする予定です。ご理解のほどよろしくお願いいたします。 取引通知 アクセスコードを設定する diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 2f51bfad1e..21edba4fa6 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -39,10 +39,12 @@ Невозможно отредактировать аккаунт Аккаунт сохранен Аккаунт для наград + Аккаунт #%s — используется для генерации адреса. Добавить аккаунт Сохранить Название аккаунта - Имя аккаунта уже существует + Аккаунт с таким названием уже существует. Пожалуйста, выберите другое название. + Название аккаунта уже используется Аккаунт Новый аккаунт Добавить аккаунт @@ -254,6 +256,7 @@ Подтвердить Подключение Обратиться в поддержку + Связаться с поддержкой Продолжить Конвертировать Копировать @@ -379,6 +382,7 @@ Поддерживаемые сети Обменять Tangem + Tangem Кошелек условия участия Условиями использования На @@ -546,6 +550,9 @@ ID: %s ID транзакции скопирован Обменяйте любой актив в вашем портфеле на этот токен + Более высокая скорость означает более быстрое подтверждение, но и более высокую сетевую комиссию. %s + Выбрать скорость + Выберите какой токен будет использоваться для оплаты комиссии сети. %s Выбрать токен Рынок и Новости В тренде @@ -834,7 +841,7 @@ Резюме Связанные новости Связанные токены - Источники + Связанные новости Будьте в курсе Функция NFC недоступна на вашем устройстве О NFT @@ -1121,6 +1128,7 @@ Сбросить карту Я понимаю, что после выполнения этого действия у меня больше не будет доступа к текущему кошельку Я понимаю, что не смогу использовать эту карту для восстановления кода доступа на других картах текущего кошелька + Я понимаю, что полностью потеряю доступ к своей карте Tangem Pay и всем средствам на ней без возможности восстановления. Сброс к заводским настройкам приведет к полному удалению кошелька с выбранной карты или кольца. Вы не сможете восстановить текущий кошелек или использовать данную карту или кольцо для восстановления кода доступа. Сброс к заводским настройкам приведет к полному удалению кошелька с выбранной карты или кольца. Вы не сможете восстановить текущий кошелек. Все Tangem девайсы были сброшены. @@ -1467,6 +1475,7 @@ Карта заморожена Обратиться в поддержку Другое + Невозможно использовать на устройствах с root-доступом. Успешно завершено Отклонено В процессе @@ -1544,6 +1553,7 @@ Посмотреть статус KYC в процессе для Tangem Pay Вы можете посмотреть текущий статус KYC или отменить его + KYC отклонено Откройте бесплатную виртуальную карту Tangem Visa Оплачивайте ежедневные покупки в USDC Открыть карту @@ -1732,7 +1742,7 @@ Импортируйте существующий кошелек через вашу фразу восстановления. Имрортировать кошелек Ввести фразу восстановления - Вы успешно сделали бэкап вашего кошелька. + Вы успешно импортировали свой кошелек. Импортировать кошелек Импорт завершен Импортировать кошелек diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml index fbf1149a65..e9f4049c3b 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -1752,7 +1752,7 @@ Імпортуйте існуючий гаманець за допомогою сід-фрази. Імпортувати гаманець Введіть фразу відновлення - Ви успішно створили резервну копію свого гаманця. + Ви успішно імпортували свій гаманець. Імпортувати гаманець Імпорт завершено Імпортувати гаманець diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index d5b33d94e7..128a5d68c7 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -323,6 +323,7 @@ No No address Not Added + Not available Not now Now OK @@ -559,6 +560,7 @@ Tangem feedback Can\'t send a transaction Coin description error + Gasless transaction fee An error occurred An error occurred. Code: %s. Requires memo @@ -821,7 +823,7 @@ Quick recap Related News Related tokens - Sources + Related news Stay in the loop NFC is not available on your device About NFT @@ -989,6 +991,7 @@ Access code restore Identical cards Access code + You can have either a mobile wallet or a hardware wallet at one time. Upgrade your wallet or delete it from the app to start using a Tangem cold wallet. All offers Available with %s Providers facilitate transactions @@ -1774,7 +1777,7 @@ Import an existing wallet with your recovery phrase. Import wallet Enter recovery phrase - You successfully backed up your wallet. + You successfully import up your wallet. Import wallet Import completed Import wallet diff --git a/data/transaction/src/main/java/com/tangem/data/transaction/DefaultGaslessTransactionRepository.kt b/data/transaction/src/main/java/com/tangem/data/transaction/DefaultGaslessTransactionRepository.kt index 3e75ce78f5..d99d586e16 100644 --- a/data/transaction/src/main/java/com/tangem/data/transaction/DefaultGaslessTransactionRepository.kt +++ b/data/transaction/src/main/java/com/tangem/data/transaction/DefaultGaslessTransactionRepository.kt @@ -16,6 +16,8 @@ import com.tangem.domain.transaction.models.GaslessTransactionData import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import java.math.BigInteger @@ -26,6 +28,8 @@ class DefaultGaslessTransactionRepository( ) : GaslessTransactionRepository { private val supportedTokensState = MutableStateFlow>>(hashMapOf()) + private val allFeeRecipientAddress = mutableSetOf() + private val addressesMutex = Mutex() private val gaslessTransactionRequestBuilder = GaslessTransactionRequestBuilder() private val signedTransactionResultConverter = GaslessSignedTransactionResultConverter() @@ -115,6 +119,21 @@ class DefaultGaslessTransactionRepository( return networkBlockchain.getChainId() ?: error("ChainId not found for blockchain ${networkBlockchain.name}") } + override suspend fun getGaslessFeeAddresses(): Set { + return addressesMutex.withLock { + allFeeRecipientAddress.ifEmpty { + val allFeeAddresses = getAllFeeRecipientAddresses() + allFeeRecipientAddress.addAll(allFeeAddresses) + allFeeRecipientAddress + } + } + } + + private suspend fun getAllFeeRecipientAddresses(): Set { + // TODO Replace with other backend call to get all fee recipient addresses when available + return setOf(getTokenFeeReceiverAddress()) + } + private companion object { val BASE_GAS_FOR_TRANSACTION: BigInteger = BigInteger("100000") } diff --git a/data/transaction/src/main/java/com/tangem/data/transaction/MockedGaslessTransactionRepository.kt b/data/transaction/src/main/java/com/tangem/data/transaction/MockedGaslessTransactionRepository.kt index dd3e5600f5..0a52be64e3 100644 --- a/data/transaction/src/main/java/com/tangem/data/transaction/MockedGaslessTransactionRepository.kt +++ b/data/transaction/src/main/java/com/tangem/data/transaction/MockedGaslessTransactionRepository.kt @@ -34,6 +34,10 @@ class MockedGaslessTransactionRepository( return networkBlockchain.getChainId() ?: error("ChainId not found for blockchain ${networkBlockchain.name}") } + override suspend fun getGaslessFeeAddresses(): Set { + return setOf("0x2bD8AA05a92CcDaeDE5d42EB7D196ed07F8F8EF3") + } + override suspend fun getTokenFeeReceiverAddress(): String { return TOKEN_RECEIVER_ADDRESS } diff --git a/data/wallet-manager/build.gradle.kts b/data/wallet-manager/build.gradle.kts index 31bb6bc3c8..e703847de0 100644 --- a/data/wallet-manager/build.gradle.kts +++ b/data/wallet-manager/build.gradle.kts @@ -26,6 +26,7 @@ dependencies { implementation(projects.domain.walletManager) implementation(projects.domain.demo) implementation(projects.domain.card) + implementation(projects.domain.transaction) api(projects.domain.models) /** Domain models */ diff --git a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/DefaultWalletManagersFacade.kt b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/DefaultWalletManagersFacade.kt index 842ce80393..c26cf7ee59 100644 --- a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/DefaultWalletManagersFacade.kt +++ b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/DefaultWalletManagersFacade.kt @@ -35,6 +35,7 @@ import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.TxInfo import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.transaction.GaslessTransactionRepository import com.tangem.domain.transaction.models.AssetRequirementsCondition import com.tangem.domain.txhistory.models.PaginationWrapper import com.tangem.domain.txhistory.models.TxHistoryState @@ -61,6 +62,7 @@ internal class DefaultWalletManagersFacade @Inject constructor( private val userWalletsStore: UserWalletsStore, private val assetLoader: AssetLoader, private val dispatchers: CoroutineDispatcherProvider, + private val gaslessTransactionRepository: GaslessTransactionRepository, blockchainSDKFactory: BlockchainSDKFactory, ) : WalletManagersFacade { @@ -284,6 +286,7 @@ internal class DefaultWalletManagersFacade @Inject constructor( items = SdkTransactionHistoryItemConverter( smartContractMethods = readSmartContractMethods(), yieldSupplyAddresses = YIELD_SUPPLY_ADDRESSES, + gaslessFeeAddresses = gaslessTransactionRepository.getGaslessFeeAddresses(), ).convertList(itemsResult.data.items), ) is Result.Failure -> error(itemsResult.error.message ?: itemsResult.error.customMessage) diff --git a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionHistoryItemConverter.kt b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionHistoryItemConverter.kt index 51d7e2fd6e..99f7e8fa99 100644 --- a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionHistoryItemConverter.kt +++ b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionHistoryItemConverter.kt @@ -9,11 +9,13 @@ import com.tangem.blockchain.transactionhistory.models.TransactionHistoryItem as internal class SdkTransactionHistoryItemConverter( smartContractMethods: Map, yieldSupplyAddresses: Set, + gaslessFeeAddresses: Set, ) : Converter { private val typeConverter by lazy { SdkTransactionTypeConverter( smartContractMethods = smartContractMethods, yieldSupplyAddresses = yieldSupplyAddresses, + gaslessFeeAddresses = gaslessFeeAddresses, ) } override fun convert(value: SdkTransactionHistoryItem): TxInfo = TxInfo( diff --git a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionTypeConverter.kt b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionTypeConverter.kt index 5096b7fe26..44850b9ec5 100644 --- a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionTypeConverter.kt +++ b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/SdkTransactionTypeConverter.kt @@ -13,8 +13,11 @@ import com.tangem.utils.converter.Converter internal class SdkTransactionTypeConverter( private val smartContractMethods: Map, private val yieldSupplyAddresses: Set, + gaslessFeeAddresses: Set, ) : Converter { + private val gaslessFeeAddressesLowercase: Set = gaslessFeeAddresses.map { it.lowercase() }.toSet() + override fun convert(value: TransactionHistoryItem): TxInfo.TransactionType { val (type, destination) = value.type to value.destinationType val source = value.sourceType @@ -125,8 +128,23 @@ internal class SdkTransactionTypeConverter( ) } "supplyTopUp" -> TxInfo.TransactionType.YieldSupply.Topup + "gaslessTransaction" -> getTypeForGaslessMethod(destination) null -> TxInfo.TransactionType.UnknownOperation else -> TxInfo.TransactionType.Operation(name = methodName.replaceFirstChar { it.titlecase() }) } ?: TxInfo.TransactionType.Operation(name = methodName?.replaceFirstChar { it.titlecase() }.orEmpty()) } + + private fun getTypeForGaslessMethod(destination: TransactionHistoryItem.DestinationType): TxInfo.TransactionType { + return when (destination) { + is TransactionHistoryItem.DestinationType.Multiple -> TxInfo.TransactionType.UnknownOperation + is TransactionHistoryItem.DestinationType.Single -> { + val address = destination.addressType.address.lowercase() + if (gaslessFeeAddressesLowercase.contains(address)) { + TxInfo.TransactionType.GaslessFee + } else { + TxInfo.TransactionType.UnknownOperation + } + } + } + } } \ No newline at end of file diff --git a/domain/legacy/src/main/assets/contract_methods.json b/domain/legacy/src/main/assets/contract_methods.json index 1ba70afcc7..5f421e8506 100644 --- a/domain/legacy/src/main/assets/contract_methods.json +++ b/domain/legacy/src/main/assets/contract_methods.json @@ -246,5 +246,10 @@ "info": "P2PEthPool", "source": "https://docs.p2p.org/", "name": "pooledUnstake" + }, + "0xaa03b617": { + "info": "GaslessTransactions", + "source": "https://github.com/tangem-developments/tangem-gasless-service", + "name": "gaslessTransaction" } } diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt index aae35a95f1..2e0c0b37b7 100644 --- a/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt @@ -107,6 +107,9 @@ data class TxInfo( @Serializable data class Operation(val name: String) : TransactionType + @Serializable + data object GaslessFee : TransactionType + @Serializable sealed interface YieldSupply : TransactionType { diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/GaslessTransactionRepository.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/GaslessTransactionRepository.kt index 29d57171a6..2f7b061892 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/GaslessTransactionRepository.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/GaslessTransactionRepository.kt @@ -63,4 +63,6 @@ interface GaslessTransactionRepository { fun getBaseGasForTransaction(): BigInteger fun getChainIdForNetwork(network: Network): Int + + suspend fun getGaslessFeeAddresses(): Set } \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt index 21045da86e..0c5e2cba45 100644 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt @@ -63,6 +63,7 @@ internal class TxHistoryItemToTransactionStateConverter( is TransactionType.UnknownOperation, is TransactionType.YieldSupply.Send, TransactionType.YieldSupply.Topup, + TransactionType.GaslessFee, -> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24 } } @@ -104,6 +105,7 @@ internal class TxHistoryItemToTransactionStateConverter( ) } is TransactionType.UnknownOperation -> resourceReference(R.string.transaction_history_operation) + TransactionType.GaslessFee -> resourceReference(R.string.gasless_transaction_fee) } private fun TxInfo.extractSubtitle(): TextReference { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt index b04f228e55..b679f01589 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt @@ -73,6 +73,7 @@ internal class TxHistoryItemStateConverter( is TransactionType.UnknownOperation, is TransactionType.YieldSupply.Send, TransactionType.YieldSupply.Topup, + TransactionType.GaslessFee, -> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24 } } @@ -114,6 +115,7 @@ internal class TxHistoryItemStateConverter( ) } is TransactionType.UnknownOperation -> resourceReference(R.string.transaction_history_operation) + TransactionType.GaslessFee -> resourceReference(R.string.gasless_transaction_fee) } private fun TxInfo.extractSubtitle(): TextReference {