Updated on 2026-08-14

This commit is contained in:
Tangem 2026-01-17 15:15:04 +03:00
parent 52cc0be3cb
commit ba4e916cd0
17 changed files with 98 additions and 13 deletions

View file

@ -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<Map<Network.ID, Set<CryptoCurrency>>>(hashMapOf())
private val allFeeRecipientAddress = mutableSetOf<String>()
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<String> {
return addressesMutex.withLock {
allFeeRecipientAddress.ifEmpty {
val allFeeAddresses = getAllFeeRecipientAddresses()
allFeeRecipientAddress.addAll(allFeeAddresses)
allFeeRecipientAddress
}
}
}
private suspend fun getAllFeeRecipientAddresses(): Set<String> {
// 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")
}

View file

@ -34,6 +34,10 @@ class MockedGaslessTransactionRepository(
return networkBlockchain.getChainId() ?: error("ChainId not found for blockchain ${networkBlockchain.name}")
}
override suspend fun getGaslessFeeAddresses(): Set<String> {
return setOf("0x2bD8AA05a92CcDaeDE5d42EB7D196ed07F8F8EF3")
}
override suspend fun getTokenFeeReceiverAddress(): String {
return TOKEN_RECEIVER_ADDRESS
}

View file

@ -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 */

View file

@ -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)

View file

@ -9,11 +9,13 @@ import com.tangem.blockchain.transactionhistory.models.TransactionHistoryItem as
internal class SdkTransactionHistoryItemConverter(
smartContractMethods: Map<String, SmartContractMethod>,
yieldSupplyAddresses: Set<String>,
gaslessFeeAddresses: Set<String>,
) : Converter<SdkTransactionHistoryItem, TxInfo> {
private val typeConverter by lazy { SdkTransactionTypeConverter(
smartContractMethods = smartContractMethods,
yieldSupplyAddresses = yieldSupplyAddresses,
gaslessFeeAddresses = gaslessFeeAddresses,
) }
override fun convert(value: SdkTransactionHistoryItem): TxInfo = TxInfo(

View file

@ -13,8 +13,11 @@ import com.tangem.utils.converter.Converter
internal class SdkTransactionTypeConverter(
private val smartContractMethods: Map<String, SmartContractMethod>,
private val yieldSupplyAddresses: Set<String>,
gaslessFeeAddresses: Set<String>,
) : Converter<TransactionHistoryItem, TxInfo.TransactionType> {
private val gaslessFeeAddressesLowercase: Set<String> = 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
}
}
}
}
}