Updated on 2026-08-14

This commit is contained in:
Tangem 2022-02-08 16:06:29 +03:00
parent c22e1bdf5b
commit c01168fd65
23 changed files with 17812 additions and 10603 deletions

View file

@ -0,0 +1,8 @@
package com.tangem.tap.common.extensions
/**
[REDACTED_AUTHOR]
*/
fun StringBuilder.appendIf(value: String, predicate: (String) -> Boolean) {
if (predicate(value)) this.append(value)
}

View file

@ -9,7 +9,7 @@ import com.squareup.moshi.Types
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.json.MoshiJsonConverter
import com.tangem.tap.common.extensions.appendIf
import com.tangem.tap.common.extensions.readJsonFileToString
import com.tangem.tap.domain.extensions.getCustomIconUrl
import com.tangem.tap.domain.extensions.setCustomIconUrl
@ -73,11 +73,7 @@ class CurrenciesRepository(val context: Application) {
return try {
tokensAdapter.fromJson(json)!!.map { it.toToken() }.distinct()
} catch (exception: Exception) {
try {
obsoleteTokensAdapter.fromJson(json)!!.map { it.toToken() }
} catch (exception: Exception) {
emptyList()
}
emptyList()
}
}
@ -109,28 +105,46 @@ class CurrenciesRepository(val context: Application) {
}
}
fun getPopularTokens(isTestNet: Boolean = false): List<Token> {
val ethereumTokensFileName =
if (isTestNet) ETHEREUM_TESTNET_TOKENS_FILE_NAME else ETHEREUM_TOKENS_FILE_NAME
val bscTokensFileName =
if (isTestNet) BSC_TESTNET_TOKENS_FILE_NAME else BSC_TOKENS_FILE_NAME
val binanceTokensFileName =
if (isTestNet) BINANCE_TESTNET_TOKENS_FILE_NAME else BINANCE_TOKENS_FILE_NAME
val avalancheTokensFileName =
if (isTestNet) AVALANCHE_TESTNET_TOKENS_FILE_NAME else AVALANCHE_TOKENS_FILE_NAME
fun getSupportedTokens(isTestNet: Boolean = false): List<Token> {
val supportedTokens = if (isTestNet) {
getSupportedTokens().mapNotNull { it.getTestnetVersion() }
} else {
getSupportedTokens()
}
val ethereumTokensJson = context.assets.readJsonFileToString(ethereumTokensFileName)
val bscTokensJson = context.assets.readJsonFileToString(bscTokensFileName)
val binanceTokensJson = context.assets.readJsonFileToString(binanceTokensFileName)
val avalancheTokensJson = context.assets.readJsonFileToString(avalancheTokensFileName)
val blockchainTokens = supportedTokens.map {
fromJsonToTokensDao(loadTokensJson(it), it)
}
val tokens = blockchainTokens.flatten().map { it.toToken() }
return tokens
}
return tokensAdapter.fromJson(ethereumTokensJson)!!.map { it.toToken() } +
tokensAdapter.fromJson(bscTokensJson)!!.map { it.toToken() } +
tokensAdapter.fromJson(binanceTokensJson)!!.mapNotNull {
// temporary exclude Binance BEP-8 tokens
if (it.type != null && it.type == BINANCE_TOKEN_TYPE_BEP8) null else it.toToken()
} +
tokensAdapter.fromJson(avalancheTokensJson)!!.map { it.toToken() }
private fun loadTokensJson(blockchain: Blockchain): String {
val fileName = getFileName(blockchain)
return context.assets.readJsonFileToString(fileName)
}
private fun getFileName(blockchain: Blockchain): String {
return StringBuilder().apply {
append(blockchain.id.toLowerCase().replace("/test", ""))
append("_tokens")
appendIf("_testnet") { blockchain.isTestnet() }
}.toString()
}
private fun fromJsonToTokensDao(tokenJson: String, blockchain: Blockchain): List<TokenDao> {
return obsoleteTokensAdapter.fromJson(tokenJson)!!.map { it.toTokenDao(blockchain) }
}
private fun getSupportedTokens(): List<Blockchain> {
return listOf(
Blockchain.Avalanche,
Blockchain.Binance,
Blockchain.BSC,
Blockchain.Ethereum,
Blockchain.Polygon,
Blockchain.Solana,
)
}
fun getBlockchains(
@ -145,35 +159,12 @@ class CurrenciesRepository(val context: Application) {
}
companion object {
private const val ETHEREUM_TOKENS_FILE_NAME = "ethereum_tokens"
private const val ETHEREUM_TESTNET_TOKENS_FILE_NAME = "ethereum_tokens_testnet"
private const val BSC_TOKENS_FILE_NAME = "bsc_tokens"
private const val BSC_TESTNET_TOKENS_FILE_NAME = "bsc_tokens_testnet"
private const val BINANCE_TOKENS_FILE_NAME = "binance_tokens"
private const val BINANCE_TESTNET_TOKENS_FILE_NAME = "binance_tokens_testnet"
private const val AVALANCHE_TOKENS_FILE_NAME = "avalanche_tokens"
private const val AVALANCHE_TESTNET_TOKENS_FILE_NAME = "avalanche_tokens_testnet"
private const val FILE_NAME_PREFIX_TOKENS = "tokens"
private const val FILE_NAME_PREFIX_BLOCKCHAINS = "blockchains"
private const val BINANCE_TOKEN_TYPE_BEP8 = "bep8"
fun getFileNameForTokens(cardId: String): String = "${FILE_NAME_PREFIX_TOKENS}_$cardId"
fun getFileNameForBlockchains(cardId: String): String =
"${FILE_NAME_PREFIX_BLOCKCHAINS}_$cardId"
fun injectDaoBlockchain(context: Context, tokenFileName: String, blockchain: Blockchain): String? {
val tokenJson = context.assets.readJsonFileToString(tokenFileName)
val converter = MoshiJsonConverter.default()
val rawTokensList = converter.fromJson<List<MutableMap<String, Any>>>(tokenJson) ?: return null
rawTokensList.forEach {
it["blockchain"] = BlockchainDao.fromBlockchain(blockchain)
}
return converter.toJson(rawTokensList)
}
}
}
@ -242,13 +233,16 @@ data class ObsoleteTokenDao(
val symbol: String,
val contractAddress: String,
val decimalCount: Int,
val customIconUrl: String?,
) {
fun toToken(): Token {
return Token(
fun toTokenDao(blockchain: Blockchain): TokenDao {
return TokenDao(
name = name,
symbol = symbol,
contractAddress = contractAddress,
decimals = decimalCount
decimalCount = decimalCount,
blockchainDao = BlockchainDao.fromBlockchain(blockchain),
customIconUrl = customIconUrl
)
}
}

View file

@ -92,7 +92,7 @@ class TwinCardsManager(
card = card
)
}
Result.failure(response.error)
Result.fromTangemSdkError(response.error)
}
}
}

View file

@ -23,7 +23,8 @@ import com.tangem.tap.common.qrCodeScan.ScanQrCodeActivity
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.common.snackBar.MaxAmountSnackbar
import com.tangem.tap.common.text.truncateMiddleWith
import com.tangem.tap.common.toggleWidget.*
import com.tangem.tap.common.toggleWidget.IndeterminateProgressButtonWidget
import com.tangem.tap.common.toggleWidget.ViewStateWidget
import com.tangem.tap.features.BaseStoreFragment
import com.tangem.tap.features.addBackPressHandler
import com.tangem.tap.features.send.redux.*
@ -40,8 +41,6 @@ import com.tangem.tap.mainScope
import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.fragment_send.*
import kotlinx.android.synthetic.main.fragment_send.rv_warning_messages
import kotlinx.android.synthetic.main.fragment_wallet.*
import kotlinx.android.synthetic.main.layout_send_address_payid.*
import kotlinx.android.synthetic.main.layout_send_amount.*
import kotlinx.android.synthetic.main.layout_send_fee.*
@ -298,7 +297,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
@ExperimentalCoroutinesApi
fun EditText.inputtedTextAsFlow(): Flow<String> = callbackFlow {
val watcher = addTextChangedListener { editable -> offer(editable?.toString() ?: "") }
val watcher = addTextChangedListener { editable -> trySend(editable?.toString() ?: "") }
awaitClose { removeTextChangedListener(watcher) }
}

View file

@ -27,6 +27,7 @@ sealed class CurrencyListItem {
createTokensList(R.string.add_tokens_subtitle_ethereum_tokens, Blockchain.Ethereum, tokens) +
createTokensList(R.string.add_tokens_subtitle_bsc_tokens, Blockchain.BSC, tokens) +
createTokensList(R.string.add_tokens_subtitle_binance_tokens, Blockchain.Binance, tokens) +
createTokensList(R.string.add_tokens_subtitle_polygon_tokens, Blockchain.Polygon, tokens) +
createTokensList(R.string.add_tokens_subtitle_avalanche_tokens, Blockchain.Avalanche, tokens)
}

View file

@ -44,7 +44,7 @@ class TokensMiddleware {
val scanResponse = store.state.globalState.scanResponse ?: return
val isTestcard = scanResponse.card.isTestCard
val tokens = currenciesRepository.getPopularTokens(isTestcard)
val tokens = currenciesRepository.getSupportedTokens(isTestcard)
val blockchains = currenciesRepository.getBlockchains(
cardFirmware = scanResponse.card.firmwareVersion,
isTestNet = isTestcard

View file

@ -121,7 +121,7 @@ fun SearchView.inputtedTextAsFlow(): Flow<String> = callbackFlow {
}
override fun onQueryTextChange(newText: String?): Boolean {
offer(newText ?: "")
trySend(newText ?: "")
return false
}
})