Updated on 2026-08-14

This commit is contained in:
Tangem 2022-04-13 10:30:27 +03:00
parent 35d74021ac
commit 0a25bbedbb
17 changed files with 224 additions and 173 deletions

View file

@ -12,7 +12,7 @@ sealed class DomainDialog : DomainStateDialog {
data class SelectTokenDialog(
val items: List<Coins.CheckAddressResponse.Token.Contract>,
val itemNameConverter: (Coins.CheckAddressResponse.Token.Contract) -> String,
val networkIdConverter: (String) -> String,
val onSelect: (Coins.CheckAddressResponse.Token.Contract) -> Unit,
val onClose: VoidCallback = {}
) : DomainDialog()

View file

@ -15,35 +15,36 @@ class AddCustomTokenManager(
suspend fun checkAddress(
contractAddress: String,
networkId: String? = null
): List<Coins.CheckAddressResponse.Token> {
): Result<List<Coins.CheckAddressResponse.Token>> {
val result = tangemTechService.coins.checkAddress(contractAddress, networkId)
return when (result) {
is Result.Success -> {
val resultTokens = result.data.tokens
val newTokensList = mutableListOf<Coins.CheckAddressResponse.Token>()
resultTokens.forEach {
val contractsWithTheSameAddress = it.contracts.filter { it.address == contractAddress }
var tokensList = mutableListOf<Coins.CheckAddressResponse.Token>()
resultTokens.forEach { token ->
val contractsWithTheSameAddress = token.contracts
.filter { it.address == contractAddress }
.filter { it.decimalCount != null }
if (contractsWithTheSameAddress.isNotEmpty()) {
val newToken = it.copy(contracts = contractsWithTheSameAddress)
newTokensList.add(newToken)
val newToken = token.copy(contracts = contractsWithTheSameAddress)
tokensList.add(newToken)
}
}
when {
if (tokensList.size > 1) {
// https://tangem.slack.com/archives/GMXC6PP71/p1649672562078679
newTokensList.size > 1 -> listOf(newTokensList[0])
else -> newTokensList
tokensList = mutableListOf(tokensList[0])
}
Result.Success(tokensList)
}
is Result.Failure -> emptyList()
is Result.Failure -> result
}
}
suspend fun tokens(): List<Coins.TokensResponse.Token> {
val result = tangemTechService.coins.tokens()
return when (result) {
return when (val result = tangemTechService.coins.tokens()) {
is Result.Success -> {
val currencies = result.data.tokens
currencies.filter {
val tokens = result.data.tokens
tokens.filter {
it.contracts.isNullOrEmpty()
}
}

View file

@ -18,4 +18,8 @@ sealed class AddCustomTokenError : AnError(ERROR_CODE_ADD_CUSTOM_TOKEN, "Add cus
sealed class AddCustomTokenWarning : AnError(ERROR_CODE_ADD_CUSTOM_TOKEN, "Add custom token - warning") {
object PotentialScamToken : AddCustomTokenWarning()
object TokenAlreadyAdded : AddCustomTokenWarning()
sealed class Network : AddCustomTokenWarning() {
object CheckAddressRequestError : Network()
}
}

View file

@ -21,7 +21,7 @@ data class TokenField(
override val id: FieldId,
) : BaseDataField<String>(id, Field.Data(""))
data class TokenNetworkField(
data class TokenBlockchainField(
override val id: FieldId,
val itemList: List<Blockchain>,
) : BaseDataField<Blockchain>(id, Field.Data(Blockchain.Unknown))

View file

@ -25,6 +25,9 @@ import org.rekotlin.Action
*/
internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomTokenHub") {
private val hubState: AddCustomTokenState
get() = domainStore.state.addCustomTokensState
override fun getHubState(storeState: DomainState): AddCustomTokenState {
return storeState.addCustomTokensState
}
@ -41,7 +44,6 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
if (action !is AddCustomTokenAction) return
// val card = storeState.globalState.scanResponse?.card
// ?: throw IllegalStateException("ScanResponse must be set before showing the AddCustomToken screen")
val hubState = storeState.addCustomTokensState
when (action) {
is OnCreate -> {
@ -102,7 +104,7 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
// dispatchOnMain()
}
is FillTokenFields -> {
val networkField = getField<TokenNetworkField>(Network, hubState)
val networkField = getField<TokenBlockchainField>(Network, hubState)
val nameField = getField<TokenField>(Name, hubState)
val symbolField = getField<TokenField>(Symbol, hubState)
val decimalsField = getField<TokenField>(Decimals, hubState)
@ -127,13 +129,22 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
): List<Coins.CheckAddressResponse.Token> {
dispatchOnMain(Screen.UpdateTokenFields(listOf(ContractAddress to ViewStates.TokenField(isLoading = true))))
val tokenManager = hubState.addCustomTokenManager
val field = getField<TokenNetworkField>(Network, hubState)
val field = getField<TokenBlockchainField>(Network, hubState)
val selectedNetworkId: String? = field.data.value.let {
if (it == Blockchain.Unknown) null else it
}?.toNetworkId()
val foundTokens = tokenManager.checkAddress(contractAddress, selectedNetworkId)
// delay(1000)
val result = when (val foundTokensResult = tokenManager.checkAddress(contractAddress, selectedNetworkId)) {
is Result.Success -> foundTokensResult.data
is Result.Failure -> {
// val warning = AddCustomTokenWarning.Network.CheckAddressRequestError
// dispatchOnMain(Warning.Add(setOf(warning)))
emptyList()
}
}
dispatchOnMain(Screen.UpdateTokenFields(listOf(ContractAddress to ViewStates.TokenField(isLoading = false))))
return foundTokens
return result
}
private suspend fun checkToken(
@ -171,12 +182,18 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
else -> {
val dialog = DomainDialog.SelectTokenDialog(
items = contracts,
itemNameConverter = { it.address },
networkIdConverter = { networkId ->
val blockchain = Blockchain.fromNetworkId(networkId)
if (blockchain == Blockchain.Unknown) {
throw DomainException.SelectTokeNetworkException(networkId)
}
AddCustomTokenState.convertBlockchainName(blockchain, "")
},
onSelect = { selectedContract ->
hubScope.launch {
// find how to connect to the upper coroutineContext and dispatch through them
dispatchOnMain(FillTokenFields(token, selectedContract))
dispatchOnMain(FillTokenFields(token, selectedContract))
dispatchOnMain(actionsLockTokenFields())
}
},
)
@ -237,7 +254,7 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
updateFormState(state)
}
is OnTokenNetworkChanged -> {
val field: TokenNetworkField = getField(Network, state)
val field: TokenBlockchainField = getField(Network, state)
field.data = action.value
updateFormState(state)
}

View file

@ -49,22 +49,17 @@ data class AddCustomTokenState(
companion object {
fun convertBlockchainName(blockchain: Blockchain, unknown: String): String = when (blockchain) {
Blockchain.Unknown -> unknown
Blockchain.Cardano -> "Cardano"
Blockchain.CardanoShelley -> "Cardano Shelley"
else -> blockchain.fullName
}
fun convertDerivationPathName(blockchain: Blockchain, unknown: String): String = when (blockchain) {
Blockchain.Unknown -> unknown
Blockchain.BSC -> "BNB Smart Chain"
Blockchain.Fantom -> "Fantom Opera"
else -> blockchain.fullName
fun convertDerivationPathLabel(blockchain: Blockchain, unknown: String): String {
return blockchain.derivationPath()?.rawPath ?: unknown
}
private fun createFormFields(): List<DataField<*>> {
return listOf(
TokenField(ContractAddress),
TokenNetworkField(Network, getSupportedNetworks()),
TokenBlockchainField(Network, getSupportedNetworks()),
TokenField(Name),
TokenField(Symbol),
TokenField(Decimals),
@ -84,6 +79,7 @@ data class AddCustomTokenState(
private fun getSupportedNetworks(): List<Blockchain> {
return listOf(
Blockchain.Unknown,
Blockchain.Ethereum,
Blockchain.BSC,
Blockchain.Binance,