diff --git a/app/src/main/assets/ethereum_tokens_testnet.json b/app/src/main/assets/ethereum_tokens_testnet.json new file mode 100644 index 0000000000..5222bbe37d --- /dev/null +++ b/app/src/main/assets/ethereum_tokens_testnet.json @@ -0,0 +1,26 @@ +[ + { + "decimalCount" : 18, + "symbol" : "WEENUS", + "name" : "Weenus", + "contractAddress" : "0xaFF4481D10270F50f203E0763e2597776068CBc5" + }, + { + "decimalCount" : 18, + "symbol" : "XEENUS", + "name" : "Xeenus", + "contractAddress" : "0x022E292b44B5a146F2e8ee36Ff44D3dd863C915c" + }, + { + "decimalCount" : 8, + "symbol" : "YEENUS", + "name" : "Yeenus", + "contractAddress" : "0xc6fDe3FD2Cc2b173aEC24cc3f267cb3Cd78a26B7" + }, + { + "decimalCount" : 0, + "symbol" : "ZEENUS", + "name" : "Zeenus", + "contractAddress" : "0x1f9061B953bBa0E36BF50F21876132DcF276fC6e" + } +] diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt b/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt index e12711e3d0..d470ae2bf6 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt @@ -1,7 +1,9 @@ package com.tangem.tap.common.extensions +import android.graphics.PorterDuff import android.widget.ImageView import android.widget.TextView +import androidx.core.content.ContextCompat import com.squareup.picasso.Callback import com.squareup.picasso.Picasso import com.tangem.blockchain.common.Blockchain @@ -48,6 +50,7 @@ fun Picasso.loadCurrenciesIcon( imageView.colorFilter = null textView.text = null } + if (blockchain.isTestnet()) imageView.tint(R.color.tint) } }) } @@ -70,12 +73,20 @@ private fun setOfflineCurrencyImage( } else { setBlockchainImage(imageView, textView, blockchain) } + if (blockchain.isTestnet()) imageView.tint(R.color.tint) +} + +fun ImageView.tint(colorRes: Int) { +// val color = ContextCompat.getColor(context, colorRes); +// ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(color)); + this.setColorFilter(ContextCompat.getColor(context, colorRes), PorterDuff.Mode.DARKEN); + } private fun setBlockchainImage( imageView: ImageView, textView: TextView, - blockchain: Blockchain + blockchain: Blockchain, ) { imageView.setImageResource(blockchain.getIconRes()) imageView.colorFilter = null @@ -85,7 +96,7 @@ private fun setBlockchainImage( private fun setTokenImage( imageView: ImageView, textView: TextView, - token: Token + token: Token, ) { imageView.setImageResource(R.drawable.shape_circle) imageView.setColorFilter(token.getColor()) diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index acdc924fd4..d0f72cd47b 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -10,6 +10,7 @@ import com.tangem.tap.common.redux.global.FiatCurrencyName import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.currenciesRepository import com.tangem.tap.domain.TapWorkarounds.isStart2Coin +import com.tangem.tap.domain.TapWorkarounds.isTestCard import com.tangem.tap.domain.configurable.config.ConfigManager import com.tangem.tap.domain.extensions.* import com.tangem.tap.domain.tasks.ScanNoteResponse @@ -96,6 +97,7 @@ class TapWalletManager { withContext(Dispatchers.Main) { store.dispatch(WalletAction.ResetState) store.dispatch(GlobalAction.SaveScanNoteResponse(data)) + store.dispatch(WalletAction.SetIfTestnetCard(data.card.isTestCard)) store.dispatch(WalletAction.MultiWallet.SetIsMultiwalletAllowed(data.card.isMultiwalletAllowed)) if (data.card.isTwinCard()) { val secondCardId = TwinsHelper.getTwinsCardId(data.card.cardId) diff --git a/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt b/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt index 5807bd024e..0c1a379a3c 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt @@ -27,7 +27,12 @@ object TapWorkarounds { } + val Card.isTestCard: Boolean + get() = cardData?.batchId == TEST_CARD_BATCH && cardId.startsWith(TEST_CARD_ID_STARTS_WITH) + private const val START_2_COIN_ISSUER = "start2coin" + private const val TEST_CARD_BATCH = "99FF" + private const val TEST_CARD_ID_STARTS_WITH = "FF99" private val excludedBatches = listOf( "0027", diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessage.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessage.kt index 3c3ad5f5ce..500f3844b3 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessage.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessage.kt @@ -1,6 +1,5 @@ package com.tangem.tap.domain.configurable.warningMessage -import android.view.View import androidx.annotation.StringRes import com.squareup.moshi.Json import com.tangem.blockchain.common.Blockchain @@ -46,7 +45,9 @@ data class WarningMessage( @Json(name = "temporary") Temporary, // можно скрыть (кнопка ОК) - AppRating + AppRating, + + TestCard } diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt index 1c59ee5c55..0e48e115e1 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt @@ -156,6 +156,18 @@ class WarningMessagesManager( messageFormatArg = remainingSignatures.toString() ) + fun testCardWarning(): WarningMessage = WarningMessage( + "", + "", + type = WarningMessage.Type.TestCard, + priority = WarningMessage.Priority.Critical, + listOf(WarningMessage.Location.MainScreen), + null, + R.string.alert_title, + R.string.warning_testnet_card_message, + WarningMessage.Origin.Local + ) + const val REMAINING_SIGNATURES_WARNING = 10 } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt b/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt index a89f4fe24c..13946dd481 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt +++ b/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt @@ -2,7 +2,6 @@ package com.tangem.tap.domain.extensions import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Token -import com.tangem.commands.common.card.EllipticCurve import java.math.BigDecimal @@ -26,17 +25,4 @@ fun Blockchain.minimalAmount(): BigDecimal { return 1.toBigDecimal().movePointLeft(decimals()) } -fun Blockchain.getSupportedCurves(): List? { - return when (this) { - Blockchain.Unknown -> null - Blockchain.Bitcoin, Blockchain.BitcoinTestnet, Blockchain.BitcoinCash, Blockchain.Litecoin, - Blockchain.Ducatus, Blockchain.Ethereum, Blockchain.EthereumTestnet, Blockchain.RSK, - Blockchain.Binance, Blockchain.BinanceTestnet -> listOf(EllipticCurve.Secp256k1) - Blockchain.Tezos, Blockchain.XRP -> listOf(EllipticCurve.Secp256k1, EllipticCurve.Ed25519) - Blockchain.Cardano, Blockchain.CardanoShelley, Blockchain.Stellar -> - listOf(EllipticCurve.Ed25519) - else -> listOf(EllipticCurve.Secp256k1) - } -} - private const val NODL = "NODL" \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt index 68a0ee5b84..88583ddf84 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt +++ b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt @@ -7,6 +7,7 @@ import com.tangem.commands.common.card.Card import com.tangem.commands.common.card.EllipticCurve import com.tangem.commands.wallet.CardWallet import com.tangem.common.extensions.hexToBytes +import com.tangem.tap.domain.TapWorkarounds.isTestCard import com.tangem.tap.domain.tasks.ScanNoteResponse import com.tangem.tap.domain.twins.isTwinCard @@ -19,28 +20,44 @@ fun WalletManagerFactory.makeWalletManagerForApp( val wallet = selectWallet(wallets) val publicKey = wallet?.publicKey ?: return null val curveToUse = wallet.curve ?: return null - return makeWalletManager(card.cardId, publicKey, blockchain, curveToUse) + return if (card.isTestCard) { + blockchain.getTestnetVersion()?.let { + makeWalletManager(card.cardId, publicKey, it, curveToUse) + } + } else { + makeWalletManager(card.cardId, publicKey, blockchain, curveToUse) + } } private fun selectWallet(wallets: List): CardWallet? { - return when (wallets.size) { - 0 -> null - 1 -> wallets[0] - else -> wallets.firstOrNull { it.curve == EllipticCurve.Secp256k1 } ?: wallets[0] - } + return when (wallets.size) { + 0 -> null + 1 -> wallets[0] + else -> wallets.firstOrNull { it.curve == EllipticCurve.Secp256k1 } ?: wallets[0] + } } fun WalletManagerFactory.makeWalletManagersForApp( card: Card, blockchains: List, ): List { - return blockchains.mapNotNull { blockchain -> makeWalletManagerForApp(card, blockchain) } + return if (card.isTestCard) { + blockchains.mapNotNull { blockchain -> + blockchain.getTestnetVersion()?.let { makeWalletManagerForApp(card, it) } + } + } else { + blockchains.mapNotNull { blockchain -> makeWalletManagerForApp(card, blockchain) } + } } fun WalletManagerFactory.makePrimaryWalletManager( data: ScanNoteResponse, ): WalletManager? { val card = data.card - val blockchain = card.getBlockchain() + val blockchain = if (card.isTestCard) { + card.getBlockchain()?.getTestnetVersion() + } else { + card.getBlockchain() + } val supportedCurves = blockchain?.getSupportedCurves() ?: return null val wallets = card.wallets.filter { wallet -> supportedCurves.contains(wallet.curve) } val wallet = selectWallet(wallets) diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt index 754d7ea239..af149d9af5 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt @@ -93,42 +93,29 @@ class CurrenciesRepository(val context: Application) { } } - fun getPopularTokens(): List { - val json = context.assets.readJsonFileToString(POPULAR_TOKENS_FILE_NAME) + fun getPopularTokens(isTestNet: Boolean = false): List { + val fileName = if (isTestNet) TESTNET_TOKENS_FILE_NAME else POPULAR_TOKENS_FILE_NAME + val json = context.assets.readJsonFileToString(fileName) return tokensAdapter.fromJson(json)!!.map { it.toToken() } } - fun getBlockchains(cardFirmware: FirmwareVersion?): List { + fun getBlockchains(cardFirmware: FirmwareVersion?, isTestNet: Boolean = false): List { return if (cardFirmware == null || cardFirmware.major < 4) { - secp256k1Blockchains + Blockchain.secp256k1Blockchains(isTestNet) } else { - secp256k1Blockchains + ed25519Blockchains + Blockchain.secp256k1Blockchains(isTestNet) + Blockchain.ed25519OnlyBlockchains(isTestNet) } } companion object { private const val POPULAR_TOKENS_FILE_NAME = "erc20_tokens" + private const val TESTNET_TOKENS_FILE_NAME = "ethereum_tokens_testnet" private const val FILE_NAME_PREFIX_TOKENS = "tokens" private const val FILE_NAME_PREFIX_BLOCKCHAINS = "blockchains" fun getFileNameForTokens(cardId: String): String = "${FILE_NAME_PREFIX_TOKENS}_$cardId" fun getFileNameForBlockchains(cardId: String): String = "${FILE_NAME_PREFIX_BLOCKCHAINS}_$cardId" - - private val secp256k1Blockchains = listOf( - Blockchain.Bitcoin, - Blockchain.BitcoinCash, - Blockchain.Binance, - Blockchain.BSC, - Blockchain.Litecoin, - Blockchain.XRP, - Blockchain.Tezos, - Blockchain.Ethereum, - Blockchain.RSK, - Blockchain.Polygon, - Blockchain.Dogecoin, - ) - private val ed25519Blockchains = listOf(Blockchain.CardanoShelley, Blockchain.Stellar) } } diff --git a/app/src/main/java/com/tangem/tap/domain/TopUpHelper.kt b/app/src/main/java/com/tangem/tap/domain/topup/TopUpHelper.kt similarity index 75% rename from app/src/main/java/com/tangem/tap/domain/TopUpHelper.kt rename to app/src/main/java/com/tangem/tap/domain/topup/TopUpHelper.kt index dfa301ab78..2ab6b843c8 100644 --- a/app/src/main/java/com/tangem/tap/domain/TopUpHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/topup/TopUpHelper.kt @@ -1,7 +1,8 @@ -package com.tangem.tap.domain +package com.tangem.tap.domain.topup import android.net.Uri import android.util.Base64 +import com.tangem.blockchain.common.Blockchain import com.tangem.tap.common.redux.global.CryptoCurrencyName import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec @@ -15,10 +16,20 @@ class TopUpHelper { private const val API_KEY_PATH = "?apiKey=" private const val CURRENCY_PATH = "¤cyCode=" private const val WALLET_ADDRESS_PATH = "&walletAddress=" -// private const val REDIRECT_URL_PATH = "&redirectUrl=" + + // private const val REDIRECT_URL_PATH = "&redirectUrl=" private const val SIGNATURE_PATH = "&signature=" - fun getUrl(cryptoCurrencyName: CryptoCurrencyName, walletAddress: String, apiKey: String, secretKey: String): String { + fun getUrl( + blockchain: Blockchain?, + cryptoCurrencyName: CryptoCurrencyName, + walletAddress: String, + apiKey: String, + secretKey: String, + ): String { + if (blockchain?.isTestnet() == true) { + return blockchain.getTestnetTopUpUrl() ?: "" + } val originalQuery = API_KEY_PATH + apiKey.urlEncode() + CURRENCY_PATH + cryptoCurrencyName.urlEncode() + WALLET_ADDRESS_PATH + walletAddress.urlEncode() @@ -41,4 +52,4 @@ class TopUpHelper { return Base64.encodeToString(sha256encoded, Base64.NO_WRAP) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/tangem/tap/domain/topup/TopUpManager.kt b/app/src/main/java/com/tangem/tap/domain/topup/TopUpManager.kt new file mode 100644 index 0000000000..568c65f7d0 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/topup/TopUpManager.kt @@ -0,0 +1,45 @@ +package com.tangem.tap.domain.topup + +import com.tangem.Message +import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager +import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.AmountType +import com.tangem.blockchain.common.Token +import com.tangem.blockchain.extensions.Result +import com.tangem.tap.common.redux.global.GlobalAction +import com.tangem.tap.domain.TangemSigner +import com.tangem.tap.store +import com.tangem.tap.tangemSdk +import java.math.BigDecimal + +class TopUpManager { + suspend fun topUpTestErc20Tokens(walletManager: EthereumWalletManager, token: Token) { + walletManager.update() + + val amountToSend = Amount(walletManager.wallet.blockchain) + val destinationAddress = token.contractAddress + + val feeResult = walletManager.getFee(amountToSend, + destinationAddress) as? Result.Success ?: return + val fee = feeResult.data[0] + + if ((walletManager.wallet.amounts[AmountType.Coin]?.value ?: BigDecimal.ZERO) < fee.value) { + return + } + + val transaction = walletManager.createTransaction(amountToSend, fee, destinationAddress) + + val signer = TangemSigner( + tangemSdk = tangemSdk, Message() + ) { signResponse -> + store.dispatch( + GlobalAction.UpdateWalletSignedHashes( + walletSignedHashes = signResponse.walletSignedHashes, + remainingSignatures = signResponse.walletRemainingSignatures, + walletPublicKey = walletManager.wallet.publicKey + ) + ) + } + walletManager.send(transaction, signer) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index 89bec71f1f..a4b1faa96b 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -12,6 +12,7 @@ import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.domain.TapWorkarounds.isTestCard import com.tangem.tap.domain.extensions.makeWalletManagerForApp import com.tangem.tap.domain.isMultiwalletAllowed import com.tangem.tap.domain.walletconnect.WalletConnectManager @@ -153,7 +154,7 @@ class WalletConnectMiddleware { wcUri = wcUri, wallet = WalletForSession( card.cardId, key.toHexString(), - isTestNet = false + isTestNet = card.isTestCard ), )) } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt index cb13d64dd0..f1bcb72e51 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.tokens.redux import com.tangem.tap.common.redux.AppState import com.tangem.tap.currenciesRepository +import com.tangem.tap.domain.TapWorkarounds.isTestCard import com.tangem.tap.features.tokens.ui.adapters.CurrencyListItem import com.tangem.tap.store import org.rekotlin.Middleware @@ -13,9 +14,13 @@ class TokensMiddleware { { action -> when (action) { is TokensAction.LoadCurrencies -> { - val cardFirmware = state()?.globalState?.scanNoteResponse?.card?.firmwareVersion - val tokens = currenciesRepository.getPopularTokens() - val blockchains = currenciesRepository.getBlockchains(cardFirmware) + val card = state()?.globalState?.scanNoteResponse?.card + val isTestcard = card?.isTestCard ?: false + val tokens = currenciesRepository.getPopularTokens(isTestcard) + val blockchains = currenciesRepository.getBlockchains( + cardFirmware = card?.firmwareVersion, + isTestNet = isTestcard + ) val currencies = CurrencyListItem.createListOfCurrencies( blockchains, tokens ) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt index ebfadb5df3..43617cb446 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt @@ -6,7 +6,6 @@ import com.tangem.blockchain.common.address.AddressType import com.tangem.commands.common.card.Card import com.tangem.tap.common.redux.ErrorAction import com.tangem.tap.common.redux.NotificationAction -import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.domain.TapError import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.tokens.CardCurrencies @@ -19,6 +18,8 @@ sealed class WalletAction : Action { object ResetState : WalletAction() + data class SetIfTestnetCard(val isTestnet: Boolean) : WalletAction() + object LoadData : WalletAction() { data class Failure(val error: TapError) : WalletAction() } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index 35b301fd50..808201e795 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -32,7 +32,8 @@ data class WalletState( val cardCurrency: CryptoCurrencyName? = null, val selectedWallet: Currency? = null, val primaryBlockchain: Blockchain? = null, - val primaryToken: Token? = null + val primaryToken: Token? = null, + val isTestnet: Boolean = false, ) : StateType { val primaryWallet = if (wallets.isNotEmpty()) wallets[0] else null @@ -49,7 +50,9 @@ data class WalletState( fun getWalletManager(token: Token?): WalletManager? { if (token == null) return null - val ethereumWalletManager = walletManagers.find { it.wallet.blockchain == Blockchain.Ethereum } + val ethereumWalletManager = walletManagers + .find { it.wallet.blockchain == Blockchain.Ethereum || + it.wallet.blockchain == Blockchain.EthereumTestnet } return if (ethereumWalletManager?.presetTokens?.contains(token) == true) { ethereumWalletManager } else { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index 905ecce398..853b1fb45b 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -8,6 +8,7 @@ import com.tangem.tap.common.redux.global.GlobalState import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.currenciesRepository +import com.tangem.tap.domain.TapWorkarounds.isTestCard import com.tangem.tap.domain.extensions.makeWalletManagerForApp import com.tangem.tap.domain.extensions.makeWalletManagersForApp import com.tangem.tap.features.wallet.redux.Currency @@ -22,7 +23,7 @@ import kotlinx.coroutines.withContext class MultiWalletMiddleware { fun handle( - action: WalletAction.MultiWallet, walletState: WalletState?, globalState: GlobalState?, + action: WalletAction.MultiWallet, walletState: WalletState?, globalState: GlobalState?, ) { when (action) { is WalletAction.MultiWallet.AddWalletManagers -> { @@ -64,7 +65,10 @@ class MultiWalletMiddleware { val cardId = globalState?.scanNoteResponse?.card?.cardId when (val currency = action.walletData.currency) { is Currency.Blockchain -> { - cardId?.let { currenciesRepository.removeBlockchain(it, currency.blockchain) } + cardId?.let { + currenciesRepository.removeBlockchain(it, + currency.blockchain) + } } is Currency.Token -> { walletState?.getWalletManager(currency.token) @@ -76,8 +80,9 @@ class MultiWalletMiddleware { is WalletAction.MultiWallet.FindBlockchainsInUse -> { val cardFirmware = globalState?.scanNoteResponse?.card?.firmwareVersion val blockchains = currenciesRepository.getBlockchains(cardFirmware) - .filterNot { walletState?.blockchains?.contains(it) == true } - val walletManagers = action.factory.makeWalletManagersForApp(action.card, blockchains) + .filterNot { walletState?.blockchains?.contains(it) == true } + val walletManagers = + action.factory.makeWalletManagersForApp(action.card, blockchains) scope.launch { walletManagers.map { walletManager -> @@ -107,10 +112,10 @@ class MultiWalletMiddleware { is WalletAction.MultiWallet.FindTokensInUse -> { val card = globalState?.scanNoteResponse?.card ?: return val walletManager = walletState?.getWalletManager(Blockchain.Ethereum) - ?: globalState.tapWalletManager.walletManagerFactory.makeWalletManagerForApp( - card = card, - blockchain = Blockchain.Ethereum - ) + ?: globalState.tapWalletManager.walletManagerFactory.makeWalletManagerForApp( + card = card, + blockchain = Blockchain.Ethereum + ) val tokenFinder = walletManager as TokenFinder scope.launch { val result = tokenFinder.findTokens() @@ -184,7 +189,7 @@ class MultiWalletMiddleware { val walletManager = walletState?.getWalletManager(token) ?: globalState.tapWalletManager.walletManagerFactory.makeWalletManagerForApp( card = card, - blockchain = Blockchain.Ethereum + blockchain = if (card.isTestCard) Blockchain.EthereumTestnet else Blockchain.Ethereum )?.also { walletManager -> store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManager)) store.dispatch(WalletAction.MultiWallet.AddBlockchain(walletManager.wallet.blockchain)) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TopUpMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TopUpMiddleware.kt index e0706570f7..98b63904ba 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TopUpMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TopUpMiddleware.kt @@ -2,9 +2,15 @@ package com.tangem.tap.features.wallet.redux.middlewares import android.net.Uri import androidx.browser.customtabs.CustomTabsIntent -import com.tangem.tap.domain.TopUpHelper +import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager +import com.tangem.tap.domain.topup.TopUpHelper +import com.tangem.tap.domain.topup.TopUpManager +import com.tangem.tap.features.wallet.redux.Currency import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.scope import com.tangem.tap.store +import kotlinx.coroutines.launch + class TopUpMiddleware { fun handle(action: WalletAction.TopUpAction) { @@ -16,16 +22,31 @@ class TopUpMiddleware { if (addresses.list.isEmpty()) return val defaultAddress = addresses.list[0].address - val url = TopUpHelper.getUrl( + val currency = selectedWalletData.currency + + if (currency is Currency.Token && currency.blockchain.isTestnet()) { + val walletManager = store.state.walletState.getWalletManager(currency.token) + if (walletManager !is EthereumWalletManager) return + + scope.launch { + TopUpManager().topUpTestErc20Tokens( + walletManager = walletManager, token = currency.token + ) + } + } else { + val url = TopUpHelper.getUrl( + currency?.blockchain, selectedWalletData.currencyData.currencySymbol!!, defaultAddress, config.moonPayApiKey, config.moonPayApiSecretKey - ) - val customTabsIntent = CustomTabsIntent.Builder() + ) + + val customTabsIntent = CustomTabsIntent.Builder() .setToolbarColor(action.toolbarColor) .build() - customTabsIntent.launchUrl(action.context, Uri.parse(url)); + customTabsIntent.launchUrl(action.context, Uri.parse(url)) + } } } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 183d55ddda..81feb660aa 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -43,7 +43,6 @@ class WalletMiddleware { is WalletAction.Warnings -> warningsMiddleware.handle(action, globalState) is WalletAction.MultiWallet -> multiWalletMiddleware.handle(action, walletState, globalState) - is WalletAction.LoadWallet -> { scope.launch { if (action.blockchain == null) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt index 0ff512dc45..32694c8282 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt @@ -12,6 +12,7 @@ import com.tangem.tap.common.analytics.AnalyticsEvent import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler import com.tangem.tap.common.extensions.isGreaterThan import com.tangem.tap.common.redux.global.GlobalState +import com.tangem.tap.domain.TapWorkarounds.isTestCard import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager import com.tangem.tap.domain.extensions.getSingleWallet @@ -84,6 +85,11 @@ class WarningsMiddleware { private fun showCardWarningsIfNeeded(globalState: GlobalState?) { globalState?.scanNoteResponse?.card?.let { card -> globalState.warningManager?.removeWarnings(WarningMessage.Origin.Local) + if (card.isTestCard) { + addWarningMessage(WarningMessagesManager.testCardWarning(), autoUpdate = true) + return@let + } + showWarningLowRemainingSignaturesIfNeeded(card) if (card.getType() != CardType.Release) { addWarningMessage(WarningMessagesManager.devCardWarning()) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index 5daef27db2..ddb3276dea 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -39,6 +39,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState { is WalletAction.MultiWallet -> newState = multiWalletReducer.reduce(action, newState) is WalletAction.ResetState -> newState = WalletState() + is WalletAction.SetIfTestnetCard -> newState = newState.copy(isTestnet = action.isTestnet) is WalletAction.EmptyWallet -> { val creatingWalletAllowed = !(newState.twinCardsState != null && newState.twinCardsState?.isCreatingTwinCardsAllowed != true) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt index 62e9849d04..b90adc2cb6 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt @@ -98,7 +98,7 @@ class WalletAdapter Picasso.get().loadCurrenciesIcon( imageView = view.iv_currency, textView = view.tv_token_letter, - token = token, blockchain = blockchain + token = token, blockchain = blockchain, ) when (wallet.currencyData.status) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt index c262bbb35c..2b793466c3 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt @@ -73,7 +73,7 @@ class WarningMessageVH(val view: View) : RecyclerView.ViewHolder(view) { } private fun setupControlButtons(warning: WarningMessage) = when (warning.type) { - WarningMessage.Type.Permanent -> { + WarningMessage.Type.Permanent, WarningMessage.Type.TestCard -> { view.group_controls_temporary.hide() view.group_controls_rating.hide() } diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index fc5a1fd7b2..de5579c26b 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -43,6 +43,8 @@ #CBE4FF #E0E6FA + #55000000 + #1C1C1E #FFB71B #CA0F03 diff --git a/app/src/main/res/values/strings_untranslated.xml b/app/src/main/res/values/strings_untranslated.xml index d6c4426536..f3a5887ec0 100644 --- a/app/src/main/res/values/strings_untranslated.xml +++ b/app/src/main/res/values/strings_untranslated.xml @@ -156,4 +156,7 @@ this wallet. This card can’t be used to establish WalletConnect session The operation couldn\'t be completed The operation couldn\'t be completed. \n\nYou have already established a WalletConnect session with this parameters. + + This is a Testnet card. Don\'t accept it as a payment. This card must only be used for testing and development purposes. +