Updated on 2026-08-14

This commit is contained in:
Tangem 2022-04-21 19:38:58 +03:00
parent 1a12b1bdf9
commit 2f7ed460ff
19 changed files with 160 additions and 252 deletions

View file

@ -1,7 +1,7 @@
package com.tangem.domain
import com.tangem.common.extensions.VoidCallback
import com.tangem.network.api.tangemTech.Coins
import com.tangem.network.api.tangemTech.CoinsResponse
/**
[REDACTED_AUTHOR]
@ -11,9 +11,9 @@ sealed interface DomainDialog {
data class DialogError(val error: DomainError) : DomainDialog
data class SelectTokenDialog(
val items: List<Coins.CheckAddressResponse.Token.Contract>,
val items: List<CoinsResponse.Coin.Network>,
val networkIdConverter: (String) -> String,
val onSelect: (Coins.CheckAddressResponse.Token.Contract) -> Unit,
val onSelect: (CoinsResponse.Coin.Network) -> Unit,
val onClose: VoidCallback = {}
) : DomainDialog
}

View file

@ -1,7 +1,7 @@
package com.tangem.domain.features.addCustomToken
import com.tangem.common.services.Result
import com.tangem.network.api.tangemTech.Coins
import com.tangem.network.api.tangemTech.CoinsResponse
import com.tangem.network.api.tangemTech.TangemTechService
/**
@ -11,41 +11,31 @@ class AddCustomTokenService(
private val tangemTechService: TangemTechService
) {
suspend fun checkAddress(
suspend fun findToken(
contractAddress: String,
networkId: String? = null
): Result<List<Coins.CheckAddressResponse.Token>> {
val result = tangemTechService.coins.checkAddress(contractAddress, networkId)
networkId: String? = null,
active: Boolean? = null,
): Result<List<CoinsResponse.Coin>> {
val result = tangemTechService.coins(contractAddress, networkId, active)
return when (result) {
is Result.Success -> {
val resultTokens = result.data.tokens
var tokensList = mutableListOf<Coins.CheckAddressResponse.Token>()
resultTokens.forEach { token ->
val contractsWithTheSameAddress = token.contracts
var coinsList = mutableListOf<CoinsResponse.Coin>()
result.data.coins.forEach { coin ->
val networksWithTheSameAddress = coin.networks
.filter { it.address != null || it.decimalCount != null }
.filter { it.address == contractAddress }
.filter { it.decimalCount != null }
if (contractsWithTheSameAddress.isNotEmpty()) {
val newToken = token.copy(contracts = contractsWithTheSameAddress)
tokensList.add(newToken)
if (networksWithTheSameAddress.isNotEmpty()) {
val newToken = coin.copy(networks = networksWithTheSameAddress)
coinsList.add(newToken)
}
}
if (tokensList.size > 1) {
if (coinsList.size > 1) {
// https://tangem.slack.com/archives/GMXC6PP71/p1649672562078679
tokensList = mutableListOf(tokensList[0])
coinsList = mutableListOf(coinsList[0])
}
Result.Success(tokensList)
Result.Success(coinsList)
}
is Result.Failure -> result
}
}
suspend fun tokens(): List<Coins.TokensResponse.Token> {
return when (val result = tangemTechService.coins.tokens()) {
is Result.Success -> {
val tokens = result.data.tokens
tokens.filter { it.contracts.isNullOrEmpty() }
}
is Result.Failure -> emptyList()
}
}
}

View file

@ -23,7 +23,7 @@ import com.tangem.domain.redux.DomainState
import com.tangem.domain.redux.dispatchOnMain
import com.tangem.domain.redux.domainStore
import com.tangem.domain.redux.global.DomainGlobalAction
import com.tangem.network.api.tangemTech.Coins
import com.tangem.network.api.tangemTech.CoinsResponse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@ -153,7 +153,7 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
}
/**
* This feature is only needed until Solana tokens are added.
* This feature is only needed until Solana coins are added.
* While they are not there - this function excludes the Solana blockchain if the user has
* filled in at least one field of the token.
*/
@ -197,7 +197,7 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
private suspend fun requestInfoAboutToken(
contractAddress: String,
): List<Coins.CheckAddressResponse.Token> {
): List<CoinsResponse.Coin> {
val tangemTechServiceManager = requireNotNull(hubState.tangemTechServiceManager)
dispatchOnMain(Screen.UpdateTokenFields(listOf(ContractAddress to ViewStates.TokenField(isLoading = true))))
@ -210,7 +210,7 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
// got the result faster than 500ms and the delay would only be the difference between them.
delay(500)
val foundTokensResult = tangemTechServiceManager.checkAddress(contractAddress, selectedNetworkId)
val foundTokensResult = tangemTechServiceManager.findToken(contractAddress, selectedNetworkId)
val result = when (foundTokensResult) {
is Result.Success -> foundTokensResult.data
is Result.Failure -> {
@ -223,7 +223,7 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
return result
}
private suspend fun manageFoundTokenChanges(foundTokens: List<Coins.CheckAddressResponse.Token>) {
private suspend fun manageFoundTokenChanges(foundTokens: List<CoinsResponse.Coin>) {
if (foundTokens.isEmpty()) {
// token not found - it's completely custom
TokenAlreadyAdded.remove()
@ -240,12 +240,12 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
val foundToken = foundTokens[0]
dispatchOnMain(SetFoundTokenId(foundToken.id))
when {
foundToken.contracts.isEmpty() -> {
foundToken.networks.isEmpty() -> {
Timber.e("Unexpected state -> throw to FB")
}
foundToken.contracts.size == 1 -> {
foundToken.networks.size == 1 -> {
// token with single contract address
val singleTokenContract = foundToken.contracts[0]
val singleTokenContract = foundToken.networks[0]
fillTokenFields(foundToken, singleTokenContract)
val isInAppSavedTokens = isTokenPersistIntoAppSavedTokensList()
@ -254,8 +254,8 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
lockAddButton()
PotentialScamToken.replace(TokenAlreadyAdded)
} else {
// not in the saved tokens list
if (singleTokenContract.active) {
// not in the saved coins list
if (foundToken.active) {
lockTokenFields()
unlockAddButton()
if (hubState.derivationPathIsSelected()) {
@ -274,7 +274,7 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
PotentialScamToken.replace(TokenAlreadyAdded)
val dialog = DomainDialog.SelectTokenDialog(
items = foundToken.contracts,
items = foundToken.networks,
networkIdConverter = { networkId ->
val blockchain = Blockchain.fromNetworkId(networkId)
if (blockchain == null || blockchain == Blockchain.Unknown) {
@ -490,14 +490,14 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
}
private suspend fun fillTokenFields(
token: Coins.CheckAddressResponse.Token,
contract: Coins.CheckAddressResponse.Token.Contract,
token: CoinsResponse.Coin,
coinNetwork: CoinsResponse.Coin.Network,
) {
val blockchain = Blockchain.fromNetworkId(contract.networkId) ?: Blockchain.Unknown
val blockchain = Blockchain.fromNetworkId(coinNetwork.networkId) ?: Blockchain.Unknown
Network.setFieldValue(Field.Data(blockchain, false))
Name.setFieldValue(Field.Data(token.name, false))
Symbol.setFieldValue(Field.Data(token.symbol, false))
Decimals.setFieldValue(Field.Data(contract.decimalCount.toString(), false))
Decimals.setFieldValue(Field.Data(coinNetwork.decimalCount.toString(), false))
dispatchOnMain(UpdateForm(hubState))
}

View file

@ -176,7 +176,7 @@ data class AddCustomTokenState(
Blockchain.Polygon,
Blockchain.Avalanche,
Blockchain.Fantom,
Blockchain.Solana, // should be unsupported for tokens until they are added to the Blockchain SDK
Blockchain.Solana, // should be unsupported for coins until they are added to the Blockchain SDK
)
if (type == CustomTokenType.Token) networks.remove(Blockchain.Solana)