From ca0a10de614ed0a5bf2dc207689512793d024b80 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 13 May 2020 18:41:41 +0300 Subject: [PATCH 1/2] Updated on 2026-08-14 --- .../bitcoin/BitcoinAddressService.kt | 92 +++++++++---------- .../bitcoin/BitcoinTransactionBuilder.kt | 18 ++-- .../bitcoin/BitcoinWalletManager.kt | 13 ++- .../bitcoin/network/BitcoinNetworkManager.kt | 29 +++--- .../BlockchainInfoApi.kt | 4 +- .../BlockchainInfoProvider.kt | 7 +- .../BlockchainInfoResponse.kt | 2 +- .../{api => blockchaininfo}/EstimateFeeApi.kt | 2 +- .../bitcoincash/BitcoinCashNetworkManager.kt | 2 +- .../BitcoinCashTransactionBuilder.kt | 6 +- .../bitcoincash/BitcoinCashWalletManager.kt | 4 +- .../ethereum/EthereumTransactionBuilder.kt | 2 +- .../network/EthereumNetworkManager.kt | 4 +- .../litecoin/LitecoinMainNetParams.java | 69 ++++++++++++++ .../litecoin/LitecoinNetworkManager.kt | 85 +++++++++++++++++ .../litecoin/LitecoinWalletManager.kt | 29 ++++++ .../tangem/blockchain/common/Blockchain.kt | 7 +- .../blockchain/common/WalletManagerFactory.kt | 19 +++- .../network/blockchair/BlockchairProvider.kt | 3 +- .../blockcypher}/BlockcypherApi.kt | 5 +- .../blockcypher}/BlockcypherProvider.kt | 42 ++++----- .../blockcypher}/BlockcypherResponse.kt | 2 +- 22 files changed, 321 insertions(+), 125 deletions(-) rename blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/{api => blockchaininfo}/BlockchainInfoApi.kt (64%) rename blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/{ => blockchaininfo}/BlockchainInfoProvider.kt (91%) rename blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/{response => blockchaininfo}/BlockchainInfoResponse.kt (93%) rename blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/{api => blockchaininfo}/EstimateFeeApi.kt (83%) create mode 100644 blockchain/src/main/java/com/tangem/blockchain/blockchains/litecoin/LitecoinMainNetParams.java create mode 100644 blockchain/src/main/java/com/tangem/blockchain/blockchains/litecoin/LitecoinNetworkManager.kt create mode 100644 blockchain/src/main/java/com/tangem/blockchain/blockchains/litecoin/LitecoinWalletManager.kt rename blockchain/src/main/java/com/tangem/blockchain/{blockchains/bitcoin/network/api => network/blockcypher}/BlockcypherApi.kt (80%) rename blockchain/src/main/java/com/tangem/blockchain/{blockchains/bitcoin/network => network/blockcypher}/BlockcypherProvider.kt (66%) rename blockchain/src/main/java/com/tangem/blockchain/{blockchains/bitcoin/network/response => network/blockcypher}/BlockcypherResponse.kt (95%) diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinAddressService.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinAddressService.kt index d4bf305e42..1483284942 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinAddressService.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinAddressService.kt @@ -1,68 +1,62 @@ package com.tangem.blockchain.blockchains.bitcoin +import com.tangem.blockchain.blockchains.litecoin.LitecoinMainNetParams import com.tangem.blockchain.common.AddressService +import com.tangem.blockchain.common.Blockchain import com.tangem.common.extensions.calculateRipemd160 import com.tangem.common.extensions.calculateSha256 -import org.bitcoinj.core.AddressFormatException -import org.bitcoinj.core.Base58 -import org.bitcoinj.core.SegwitAddress +import org.bitcoinj.core.* import org.bitcoinj.params.MainNetParams import org.bitcoinj.params.TestNet3Params import java.security.MessageDigest -class BitcoinAddressService(private val testNet: Boolean = false): AddressService { +class BitcoinAddressService(private val blockchain: Blockchain) : AddressService { + + private val networkParameters: NetworkParameters = when (blockchain) { + Blockchain.Bitcoin -> MainNetParams() + Blockchain.BitcoinTestnet -> TestNet3Params() + Blockchain.Litecoin -> LitecoinMainNetParams() + else -> throw Exception("${blockchain.fullName} blockchain is not supported by ${this::class.simpleName}") + } + override fun makeAddress(walletPublicKey: ByteArray): String { - val netSelectionByte = if (testNet) 0x6f.toByte() else 0x00.toByte() - val hash1 = walletPublicKey.calculateSha256().calculateRipemd160() - val hash2 = byteArrayOf(netSelectionByte).plus(hash1).calculateSha256().calculateSha256() - val result = byteArrayOf(netSelectionByte) + hash1 + hash2[0] + hash2[1] + hash2[2] + hash2[3] - return Base58.encode(result) - } + val publicKeyHash = walletPublicKey.calculateSha256().calculateRipemd160() + val checksum = byteArrayOf(networkParameters.addressHeader.toByte()).plus(publicKeyHash) + .calculateSha256().calculateSha256() + val result = byteArrayOf(networkParameters.addressHeader.toByte()) + publicKeyHash + checksum.copyOfRange(0, 4) + return Base58.encode(result) + } - override fun validate(address: String): Boolean { - if (firstLetters.contains(address.first())) { - if (testNet && firstLettersNonTestNet.contains(address.first())) return false - if (address.length !in 26..35) return false - val decoded = address.decodeBase58() ?: return false - val hash = recursiveSha256(decoded, 0, 21, 2) - return hash.sliceArray(0..3).contentEquals(decoded.sliceArray(21..24)) - } else { - return validateSegwitAddress(address, testNet) + override fun validate(address: String): Boolean { + return validateLegacyAddress(address) || validateSegwitAddress(address) + } + + private fun validateSegwitAddress(address: String): Boolean { + return try { + when (blockchain) { + Blockchain.Bitcoin -> SegwitAddress.fromBech32(MainNetParams(), address) + Blockchain.BitcoinTestnet -> SegwitAddress.fromBech32(TestNet3Params(), address) + Blockchain.Litecoin -> SegwitAddress.fromBech32(LitecoinMainNetParams(), address) + else -> return false } + true + } catch (e: Exception) { + false } + } - private fun recursiveSha256(data: ByteArray, start: Int, len: Int, recursion: Int): ByteArray { - if (recursion == 0) return data - val md = MessageDigest.getInstance("SHA-256") - md.update(data.sliceArray(start until start + len)) - return recursiveSha256(md.digest(), 0, 32, recursion - 1) - } - - private fun String.decodeBase58(): ByteArray? { - return try { - Base58.decode(this) - } catch (exception: AddressFormatException) { - null + private fun validateLegacyAddress(address: String): Boolean { + return try { + when (blockchain) { + Blockchain.Bitcoin -> LegacyAddress.fromBase58(MainNetParams(), address) + Blockchain.BitcoinTestnet -> LegacyAddress.fromBase58(TestNet3Params(), address) + Blockchain.Litecoin -> LegacyAddress.fromBase58(LitecoinMainNetParams(), address) + else -> return false } + true + } catch (e: Exception) { + false } - - private fun validateSegwitAddress(address: String, testNet: Boolean): Boolean { - return try { - if (testNet) { - SegwitAddress.fromBech32(TestNet3Params(), address) - true - } else { - SegwitAddress.fromBech32(MainNetParams(), address) - true - } - } catch (e: Exception) { - false - } - } - - companion object { - private const val firstLetters = "123nm" - private const val firstLettersNonTestNet = "13" } } \ No newline at end of file diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinTransactionBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinTransactionBuilder.kt index ef0cbe5500..ede62d31a4 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinTransactionBuilder.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinTransactionBuilder.kt @@ -1,21 +1,30 @@ package com.tangem.blockchain.blockchains.bitcoin +import com.tangem.blockchain.blockchains.litecoin.LitecoinMainNetParams +import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.TransactionData import com.tangem.blockchain.extensions.Result import com.tangem.common.extensions.isZero import org.bitcoinj.core.* import org.bitcoinj.crypto.TransactionSignature +import org.bitcoinj.params.MainNetParams +import org.bitcoinj.params.TestNet3Params import org.bitcoinj.script.Script import org.bitcoinj.script.ScriptBuilder import java.math.BigDecimal import java.math.BigInteger open class BitcoinTransactionBuilder( - private val walletPublicKey: ByteArray, private val testNet: Boolean = false + private val walletPublicKey: ByteArray, blockchain: Blockchain ) { private lateinit var transaction: Transaction - protected var networkParameters: NetworkParameters? = null + protected var networkParameters = when (blockchain) { + Blockchain.Bitcoin, Blockchain.BitcoinCash -> MainNetParams() + Blockchain.BitcoinTestnet -> TestNet3Params() + Blockchain.Litecoin -> LitecoinMainNetParams() + else -> throw Exception("${blockchain.fullName} blockchain is not supported by ${this::class.simpleName}") + } var unspentOutputs: List? = null open fun buildToSign( @@ -25,11 +34,6 @@ open class BitcoinTransactionBuilder( val change: BigDecimal = calculateChange(transactionData, unspentOutputs!!) - networkParameters = if (testNet) { - NetworkParameters.fromID(NetworkParameters.ID_TESTNET) - } else { - NetworkParameters.fromID(NetworkParameters.ID_MAINNET) - } transaction = transactionData.toBitcoinJTransaction(networkParameters, unspentOutputs!!, change) val hashesForSign: MutableList = MutableList(transaction.inputs.size) { byteArrayOf() } diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinWalletManager.kt index 0670f32ad4..2a723fe5f9 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinWalletManager.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinWalletManager.kt @@ -74,11 +74,16 @@ open class BitcoinWalletManager( val minFee = feeResult.data.minimalPerKb.calculateFee(transactionSize) val normalFee = feeResult.data.normalPerKb.calculateFee(transactionSize) val priorityFee = feeResult.data.priorityPerKb.calculateFee(transactionSize) - return Result.Success( - listOf(Amount(minFee, blockchain), - Amount(normalFee, blockchain), - Amount(priorityFee, blockchain)) + val fees = listOf(Amount(minFee, blockchain), + Amount(normalFee, blockchain), + Amount(priorityFee, blockchain) ) + + val minimalFee = transactionSize.movePointLeft(blockchain.decimals()) + for (fee in fees) { + if (fee.value!! < minimalFee) fee.value = minimalFee + } + return Result.Success(fees) } } } diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/BitcoinNetworkManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/BitcoinNetworkManager.kt index 8483883d82..c6190937a4 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/BitcoinNetworkManager.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/BitcoinNetworkManager.kt @@ -1,26 +1,29 @@ package com.tangem.blockchain.blockchains.bitcoin.network import com.tangem.blockchain.blockchains.bitcoin.BitcoinUnspentOutput -import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockchainInfoApi -import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockcypherApi -import com.tangem.blockchain.blockchains.bitcoin.network.api.EstimatefeeApi +import com.tangem.blockchain.blockchains.bitcoin.network.blockchaininfo.BlockchainInfoApi +import com.tangem.blockchain.blockchains.bitcoin.network.blockchaininfo.BlockchainInfoProvider +import com.tangem.blockchain.network.blockcypher.BlockcypherApi +import com.tangem.blockchain.blockchains.bitcoin.network.blockchaininfo.EstimatefeeApi +import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.extensions.Result import com.tangem.blockchain.extensions.SimpleResult import com.tangem.blockchain.network.API_BLOCKCHAIN_INFO import com.tangem.blockchain.network.API_BLOCKCYPHER import com.tangem.blockchain.network.API_ESTIMATEFEE +import com.tangem.blockchain.network.blockcypher.BlockcypherProvider import com.tangem.blockchain.network.createRetrofitInstance import retrofit2.HttpException import java.io.IOException import java.math.BigDecimal -class BitcoinNetworkManager(private val isTestNet: Boolean = false) : BitcoinProvider { +class BitcoinNetworkManager(blockchain: Blockchain) : BitcoinProvider { private val blockcypherProvider by lazy { val api = createRetrofitInstance(API_BLOCKCYPHER) .create(BlockcypherApi::class.java) - BlockcypherProvider(api, isTestNet) + BlockcypherProvider(api, blockchain) } private val blockchainInfoProvider by lazy { @@ -31,10 +34,10 @@ class BitcoinNetworkManager(private val isTestNet: Boolean = false) : BitcoinPro BlockchainInfoProvider(api, estimateFeeApi) } - private var bitcoinProvider: BitcoinProvider = blockchainInfoProvider + private var provider: BitcoinProvider = blockchainInfoProvider private fun changeProvider() { - bitcoinProvider = if (bitcoinProvider == blockchainInfoProvider) { + provider = if (provider == blockchainInfoProvider) { blockcypherProvider } else { blockchainInfoProvider @@ -42,13 +45,13 @@ class BitcoinNetworkManager(private val isTestNet: Boolean = false) : BitcoinPro } override suspend fun getInfo(address: String): Result { - val result = bitcoinProvider.getInfo(address) + val result = provider.getInfo(address) when (result) { is Result.Success -> return result is Result.Failure -> { if (result.error is IOException || result.error is HttpException) { changeProvider() - return bitcoinProvider.getInfo(address) + return provider.getInfo(address) } else { return result } @@ -57,13 +60,13 @@ class BitcoinNetworkManager(private val isTestNet: Boolean = false) : BitcoinPro } override suspend fun getFee(): Result { - val result = bitcoinProvider.getFee() + val result = provider.getFee() when (result) { is Result.Success -> return result is Result.Failure -> { if (result.error is IOException || result.error is HttpException) { changeProvider() - return bitcoinProvider.getFee() + return provider.getFee() } else { return result } @@ -72,13 +75,13 @@ class BitcoinNetworkManager(private val isTestNet: Boolean = false) : BitcoinPro } override suspend fun sendTransaction(transaction: String): SimpleResult { - val result = bitcoinProvider.sendTransaction(transaction) + val result = provider.sendTransaction(transaction) when (result) { is SimpleResult.Success -> return result is SimpleResult.Failure -> { if (result.error is IOException || result.error is HttpException) { changeProvider() - return bitcoinProvider.sendTransaction(transaction) + return provider.sendTransaction(transaction) } else { return result } diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/api/BlockchainInfoApi.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/blockchaininfo/BlockchainInfoApi.kt similarity index 64% rename from blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/api/BlockchainInfoApi.kt rename to blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/blockchaininfo/BlockchainInfoApi.kt index 294846b58c..2f1884dcb3 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/api/BlockchainInfoApi.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/blockchaininfo/BlockchainInfoApi.kt @@ -1,7 +1,5 @@ -package com.tangem.blockchain.blockchains.bitcoin.network.api +package com.tangem.blockchain.blockchains.bitcoin.network.blockchaininfo -import com.tangem.blockchain.blockchains.bitcoin.network.response.BlockchainInfoAddress -import com.tangem.blockchain.blockchains.bitcoin.network.response.BlockchainInfoUnspents import okhttp3.ResponseBody import retrofit2.http.* diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/BlockchainInfoProvider.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/blockchaininfo/BlockchainInfoProvider.kt similarity index 91% rename from blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/BlockchainInfoProvider.kt rename to blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/blockchaininfo/BlockchainInfoProvider.kt index cb9dc12e6a..ee177be908 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/BlockchainInfoProvider.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/blockchaininfo/BlockchainInfoProvider.kt @@ -1,8 +1,9 @@ -package com.tangem.blockchain.blockchains.bitcoin.network +package com.tangem.blockchain.blockchains.bitcoin.network.blockchaininfo import com.tangem.blockchain.blockchains.bitcoin.BitcoinUnspentOutput -import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockchainInfoApi -import com.tangem.blockchain.blockchains.bitcoin.network.api.EstimatefeeApi +import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinAddressResponse +import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinFee +import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinProvider import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.extensions.Result import com.tangem.blockchain.extensions.SimpleResult diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/response/BlockchainInfoResponse.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/blockchaininfo/BlockchainInfoResponse.kt similarity index 93% rename from blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/response/BlockchainInfoResponse.kt rename to blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/blockchaininfo/BlockchainInfoResponse.kt index e7ec0f2734..38e3035552 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/response/BlockchainInfoResponse.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/blockchaininfo/BlockchainInfoResponse.kt @@ -1,4 +1,4 @@ -package com.tangem.blockchain.blockchains.bitcoin.network.response +package com.tangem.blockchain.blockchains.bitcoin.network.blockchaininfo import com.squareup.moshi.Json import com.squareup.moshi.JsonClass diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/api/EstimateFeeApi.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/blockchaininfo/EstimateFeeApi.kt similarity index 83% rename from blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/api/EstimateFeeApi.kt rename to blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/blockchaininfo/EstimateFeeApi.kt index 393e03a00b..43d9cc42f9 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/api/EstimateFeeApi.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/blockchaininfo/EstimateFeeApi.kt @@ -1,4 +1,4 @@ -package com.tangem.blockchain.blockchains.bitcoin.network.api +package com.tangem.blockchain.blockchains.bitcoin.network.blockchaininfo import retrofit2.http.GET diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoincash/BitcoinCashNetworkManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoincash/BitcoinCashNetworkManager.kt index 5a594aa312..d4ad5981bf 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoincash/BitcoinCashNetworkManager.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoincash/BitcoinCashNetworkManager.kt @@ -12,7 +12,7 @@ import com.tangem.blockchain.network.blockchair.BlockchairProvider import com.tangem.blockchain.network.createRetrofitInstance class BitcoinCashNetworkManager : BitcoinProvider { - private val blockchain: Blockchain = Blockchain.BitcoinCash + private val blockchain = Blockchain.BitcoinCash private val blockchairProvider by lazy { val api = createRetrofitInstance(API_BLOCKCHAIR).create(BlockchairApi::class.java) diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoincash/BitcoinCashTransactionBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoincash/BitcoinCashTransactionBuilder.kt index 58bec1f6e3..cb3dff45a6 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoincash/BitcoinCashTransactionBuilder.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoincash/BitcoinCashTransactionBuilder.kt @@ -2,6 +2,7 @@ package com.tangem.blockchain.blockchains.bitcoincash import com.tangem.blockchain.blockchains.bitcoin.BitcoinTransactionBuilder import com.tangem.blockchain.blockchains.bitcoin.BitcoinUnspentOutput +import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.TransactionData import com.tangem.blockchain.extensions.Result import com.tangem.common.extensions.isZero @@ -13,8 +14,8 @@ import org.bitcoinj.script.ScriptBuilder import java.math.BigDecimal import java.math.BigInteger -class BitcoinCashTransactionBuilder(private val walletPublicKey: ByteArray) - : BitcoinTransactionBuilder(walletPublicKey) { +class BitcoinCashTransactionBuilder(private val walletPublicKey: ByteArray, blockchain: Blockchain) + : BitcoinTransactionBuilder(walletPublicKey, blockchain) { private lateinit var transaction: BitcoinCashTransaction @@ -25,7 +26,6 @@ class BitcoinCashTransactionBuilder(private val walletPublicKey: ByteArray) val change: BigDecimal = calculateChange(transactionData, unspentOutputs!!) - networkParameters = NetworkParameters.fromID(NetworkParameters.ID_MAINNET) transaction = transactionData.toBitcoinCashTransaction(networkParameters, unspentOutputs!!, change) val hashesForSign: MutableList = MutableList(transaction.inputs.size) { byteArrayOf() } diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoincash/BitcoinCashWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoincash/BitcoinCashWalletManager.kt index b0793c6cf9..2d2d310ec2 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoincash/BitcoinCashWalletManager.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoincash/BitcoinCashWalletManager.kt @@ -10,8 +10,8 @@ import java.math.BigDecimal class BitcoinCashWalletManager( cardId: String, wallet: Wallet, - private val transactionBuilder: BitcoinCashTransactionBuilder, - private val networkManager: BitcoinCashNetworkManager + transactionBuilder: BitcoinCashTransactionBuilder, + networkManager: BitcoinCashNetworkManager ) : BitcoinWalletManager(cardId, wallet, transactionBuilder, networkManager), TransactionSender { override suspend fun getFee(amount: Amount, destination: String): Result> { val minimalFee = BigDecimal("0.00001") diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/EthereumTransactionBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/EthereumTransactionBuilder.kt index ead68d974b..74d554ccb9 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/EthereumTransactionBuilder.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/EthereumTransactionBuilder.kt @@ -22,7 +22,7 @@ class EthereumTransactionBuilder(private val walletPublicKey: ByteArray, blockch private val chainId = when (blockchain) { Blockchain.Ethereum -> Chain.Mainnet.id Blockchain.RSK -> Chain.RskMainnet.id - else -> throw Exception("${blockchain.fullName} blockchain is not supported by EthereumTransactionBuilder") + else -> throw Exception("${blockchain.fullName} blockchain is not supported by ${this::class.simpleName}") } fun buildToSign(transactionData: TransactionData, nonce: BigInteger?): TransactionToSign? { diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/network/EthereumNetworkManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/network/EthereumNetworkManager.kt index 0fd3078d40..b5da72dd74 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/network/EthereumNetworkManager.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/network/EthereumNetworkManager.kt @@ -23,7 +23,7 @@ class EthereumNetworkManager(blockchain: Blockchain) { val baseUrl = when (blockchain) { Blockchain.Ethereum -> API_INFURA + infuraPath Blockchain.RSK -> API_RSK - else -> throw Exception("${blockchain.fullName} blockchain is not supported by EthereumNetworkManager") + else -> throw Exception("${blockchain.fullName} blockchain is not supported by ${this::class.simpleName}") } createRetrofitInstance(baseUrl).create(EthereumApi::class.java) } @@ -31,7 +31,7 @@ class EthereumNetworkManager(blockchain: Blockchain) { private val apiKey = when (blockchain) { Blockchain.Ethereum -> INFURA_API_KEY Blockchain.RSK -> "" - else -> throw Exception("${blockchain.fullName} blockchain is not supported by EthereumNetworkManager") + else -> throw Exception("${blockchain.fullName} blockchain is not supported by ${this::class.simpleName}") } private val provider: EthereumProvider by lazy { EthereumProvider(api, apiKey) } diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/litecoin/LitecoinMainNetParams.java b/blockchain/src/main/java/com/tangem/blockchain/blockchains/litecoin/LitecoinMainNetParams.java new file mode 100644 index 0000000000..1329dfe69c --- /dev/null +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/litecoin/LitecoinMainNetParams.java @@ -0,0 +1,69 @@ +package com.tangem.blockchain.blockchains.litecoin; + +import org.bitcoinj.core.Utils; +import org.bitcoinj.params.AbstractBitcoinNetParams; +import org.bitcoinj.params.MainNetParams; +import org.spongycastle.util.encoders.Hex; + +import static com.google.common.base.Preconditions.checkState; + + +public class LitecoinMainNetParams extends AbstractBitcoinNetParams { + public static final int MAINNET_MAJORITY_WINDOW = MainNetParams.MAINNET_MAJORITY_WINDOW; + public static final int MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED = MainNetParams.MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED; + public static final int MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE = MainNetParams.MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE; + + public LitecoinMainNetParams() { + super(); + id = "org.bitcoinj.litecoin_mainnet"; + // Genesis hash is 12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2 + packetMagic = 0xfbc0b6db; + + maxTarget = Utils.decodeCompactBits(0x1e0fffffL); + port = 9333; + addressHeader = 48; + p2shHeader = 50; + segwitAddressHrp = "ltc"; + dumpedPrivateKeyHeader = 176; + + spendableCoinbaseDepth = 100; + subsidyDecreaseBlockCount = 840000; + + genesisBlock.setTime(1317972665L); + genesisBlock.setDifficultyTarget(0x1e0ffff0L); + genesisBlock.setNonce(2084524493); + + String genesisHash = genesisBlock.getHashAsString(); + checkState(genesisHash.equals("5155a7ed2219a75c0735c58b5d459c6d07d97917570e27b9d1d4546fb8431381")); + alertSigningKey = Hex.decode("040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9"); + + majorityEnforceBlockUpgrade = MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE; + majorityRejectBlockOutdated = MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED; + majorityWindow = MAINNET_MAJORITY_WINDOW; + + dnsSeeds = new String[]{ + "dnsseed.litecointools.com", + "dnsseed.litecoinpool.org", + "dnsseed.ltc.xurious.com", + "dnsseed.koin-project.com", + "dnsseed.weminemnc.com" + }; + bip32HeaderP2PKHpub = 0x0488B21E; + bip32HeaderP2PKHpriv = 0x0488ADE4; + } + + @Override + public String getPaymentProtocolId() { + return PAYMENT_PROTOCOL_ID_MAINNET; + } + + + private static LitecoinMainNetParams instance; + + public static synchronized LitecoinMainNetParams get() { + if (instance == null) { + instance = new LitecoinMainNetParams(); + } + return instance; + } +} \ No newline at end of file diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/litecoin/LitecoinNetworkManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/litecoin/LitecoinNetworkManager.kt new file mode 100644 index 0000000000..95e5e592ce --- /dev/null +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/litecoin/LitecoinNetworkManager.kt @@ -0,0 +1,85 @@ +package com.tangem.blockchain.blockchains.litecoin + +import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinAddressResponse +import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinFee +import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinProvider +import com.tangem.blockchain.network.blockcypher.BlockcypherProvider +import com.tangem.blockchain.network.blockcypher.BlockcypherApi +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.extensions.Result +import com.tangem.blockchain.extensions.SimpleResult +import com.tangem.blockchain.network.API_BLOCKCHAIR +import com.tangem.blockchain.network.API_BLOCKCYPHER +import com.tangem.blockchain.network.blockchair.BlockchairApi +import com.tangem.blockchain.network.blockchair.BlockchairProvider +import com.tangem.blockchain.network.createRetrofitInstance +import retrofit2.HttpException +import java.io.IOException + + +class LitecoinNetworkManager : BitcoinProvider { + private val blockchain = Blockchain.Litecoin + + private val blockchairProvider by lazy { + val api = createRetrofitInstance(API_BLOCKCHAIR) + .create(BlockchairApi::class.java) + BlockchairProvider(api, blockchain) + } + + private val blockcypherProvider by lazy { + val api = createRetrofitInstance(API_BLOCKCYPHER) + .create(BlockcypherApi::class.java) + BlockcypherProvider(api, blockchain) + } + + private var provider: BitcoinProvider = blockchairProvider + + private fun changeProvider() { + provider = if (provider == blockchairProvider) blockcypherProvider else blockchairProvider + } + + override suspend fun getInfo(address: String): Result { + val result = provider.getInfo(address) + when (result) { + is Result.Success -> return result + is Result.Failure -> { + if (result.error is IOException || result.error is HttpException) { + changeProvider() + return provider.getInfo(address) + } else { + return result + } + } + } + } + + override suspend fun getFee(): Result { + val result = provider.getFee() + when (result) { + is Result.Success -> return result + is Result.Failure -> { + if (result.error is IOException || result.error is HttpException) { + changeProvider() + return provider.getFee() + } else { + return result + } + } + } + } + + override suspend fun sendTransaction(transaction: String): SimpleResult { + val result = provider.sendTransaction(transaction) + when (result) { + is SimpleResult.Success -> return result + is SimpleResult.Failure -> { + if (result.error is IOException || result.error is HttpException) { + changeProvider() + return provider.sendTransaction(transaction) + } else { + return result + } + } + } + } +} \ No newline at end of file diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/litecoin/LitecoinWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/litecoin/LitecoinWalletManager.kt new file mode 100644 index 0000000000..8c12297f26 --- /dev/null +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/litecoin/LitecoinWalletManager.kt @@ -0,0 +1,29 @@ +package com.tangem.blockchain.blockchains.litecoin + +import com.tangem.blockchain.blockchains.bitcoin.BitcoinTransactionBuilder +import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager +import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.TransactionSender +import com.tangem.blockchain.common.Wallet +import com.tangem.blockchain.extensions.Result +import java.math.BigDecimal + +class LitecoinWalletManager( + cardId: String, + wallet: Wallet, + transactionBuilder: BitcoinTransactionBuilder, + networkManager: LitecoinNetworkManager +) : BitcoinWalletManager(cardId, wallet, transactionBuilder, networkManager), TransactionSender { + override suspend fun getFee(amount: Amount, destination: String): Result> { + val minimalFee = BigDecimal("0.00001") + when (val result = super.getFee(amount, destination)) { + is Result.Success -> { + for (fee in result.data) { + if (fee.value!! < minimalFee) fee.value = minimalFee + } + return result + } + is Result.Failure -> return result + } + } +} \ No newline at end of file diff --git a/blockchain/src/main/java/com/tangem/blockchain/common/Blockchain.kt b/blockchain/src/main/java/com/tangem/blockchain/common/Blockchain.kt index c579c2d3db..9284ec26b8 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/common/Blockchain.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/common/Blockchain.kt @@ -17,6 +17,7 @@ enum class Blockchain( Bitcoin("BTC", "BTC", "Bitcoin"), BitcoinTestnet("BTC/test", "BTCt", "Bitcoin Testnet"), BitcoinCash("BCH", "BCH", "Bitcoin Cash"), + Litecoin("LTC", "LTC", "Litecoin"), Ethereum("ETH", "ETH", "Ethereum"), RSK("RSK", "RBTC", "RSK"), Cardano("CARDANO", "ADA", "Cardano"), @@ -26,7 +27,7 @@ enum class Blockchain( Stellar("XLM", "XLM", "Stellar"); fun decimals(): Int = when (this) { - Bitcoin, BitcoinTestnet, BitcoinCash, Binance, BinanceTestnet -> 8 + Bitcoin, BitcoinTestnet, BitcoinCash, Binance, BinanceTestnet, Litecoin -> 8 Cardano, XRP -> 6 Ethereum, RSK -> 18 Stellar -> 7 @@ -43,8 +44,7 @@ enum class Blockchain( private fun getAddressService(): AddressService = when (this) { Unknown -> throw Exception("unsupported blockchain") - Bitcoin -> BitcoinAddressService() - BitcoinTestnet -> BitcoinAddressService(true) + Bitcoin, BitcoinTestnet, Litecoin -> BitcoinAddressService(this) BitcoinCash -> BitcoinCashAddressService() Ethereum, RSK -> EthereumAddressService() Cardano -> CardanoAddressService() @@ -66,6 +66,7 @@ enum class Blockchain( Bitcoin -> "https://blockchain.info/address/$address" BitcoinTestnet -> "https://live.blockcypher.com/btc-testnet/address/$address" BitcoinCash -> "https://blockchair.com/bitcoin-cash/address/$address" + Litecoin -> "https://live.blockcypher.com/ltc/address/$address" Cardano -> "https://cardanoexplorer.com/address/$address" Ethereum -> if (token == null) { "https://etherscan.io/address/" diff --git a/blockchain/src/main/java/com/tangem/blockchain/common/WalletManagerFactory.kt b/blockchain/src/main/java/com/tangem/blockchain/common/WalletManagerFactory.kt index 621ed2f129..2f3d29bc18 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/common/WalletManagerFactory.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/common/WalletManagerFactory.kt @@ -15,6 +15,8 @@ import com.tangem.blockchain.blockchains.cardano.network.CardanoNetworkManager import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionBuilder import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager import com.tangem.blockchain.blockchains.ethereum.network.EthereumNetworkManager +import com.tangem.blockchain.blockchains.litecoin.LitecoinNetworkManager +import com.tangem.blockchain.blockchains.litecoin.LitecoinWalletManager import com.tangem.blockchain.blockchains.stellar.StellarNetworkManager import com.tangem.blockchain.blockchains.stellar.StellarTransactionBuilder @@ -42,24 +44,31 @@ object WalletManagerFactory { Blockchain.Bitcoin -> { return BitcoinWalletManager( cardId, wallet, - BitcoinTransactionBuilder(walletPublicKey), - BitcoinNetworkManager() + BitcoinTransactionBuilder(walletPublicKey, blockchain), + BitcoinNetworkManager(blockchain) ) } Blockchain.BitcoinTestnet -> { return BitcoinWalletManager( cardId, wallet, - BitcoinTransactionBuilder(walletPublicKey, true), - BitcoinNetworkManager(true) + BitcoinTransactionBuilder(walletPublicKey, blockchain), + BitcoinNetworkManager(blockchain) ) } Blockchain.BitcoinCash -> { return BitcoinCashWalletManager( cardId, wallet, - BitcoinCashTransactionBuilder(walletPublicKey.toCompressedPublicKey()), + BitcoinCashTransactionBuilder(walletPublicKey.toCompressedPublicKey(), blockchain), BitcoinCashNetworkManager() ) } + Blockchain.Litecoin -> { + return LitecoinWalletManager( + cardId, wallet, + BitcoinTransactionBuilder(walletPublicKey, blockchain), + LitecoinNetworkManager() + ) + } Blockchain.Ethereum, Blockchain.RSK -> { return EthereumWalletManager( cardId, wallet, diff --git a/blockchain/src/main/java/com/tangem/blockchain/network/blockchair/BlockchairProvider.kt b/blockchain/src/main/java/com/tangem/blockchain/network/blockchair/BlockchairProvider.kt index a14c6b8561..69e8111e66 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/network/blockchair/BlockchairProvider.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/network/blockchair/BlockchairProvider.kt @@ -15,7 +15,8 @@ import java.math.RoundingMode class BlockchairProvider(private val api: BlockchairApi, blockchain: Blockchain) : BitcoinProvider { private val blockchainPath = when (blockchain) { Blockchain.BitcoinCash -> "bitcoin-cash" - else -> throw Exception("${blockchain.fullName} blockchain is not supported by BlockchairProvider") + Blockchain.Litecoin -> "litecoin" + else -> throw Exception("${blockchain.fullName} blockchain is not supported by ${this::class.simpleName}") } private val decimals = blockchain.decimals() diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/api/BlockcypherApi.kt b/blockchain/src/main/java/com/tangem/blockchain/network/blockcypher/BlockcypherApi.kt similarity index 80% rename from blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/api/BlockcypherApi.kt rename to blockchain/src/main/java/com/tangem/blockchain/network/blockcypher/BlockcypherApi.kt index 14b78b0e53..77ea5eaf45 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/api/BlockcypherApi.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/network/blockcypher/BlockcypherApi.kt @@ -1,9 +1,6 @@ -package com.tangem.blockchain.blockchains.bitcoin.network.api +package com.tangem.blockchain.network.blockcypher import com.squareup.moshi.JsonClass -import com.tangem.blockchain.blockchains.bitcoin.network.response.BlockcypherFee -import com.tangem.blockchain.blockchains.bitcoin.network.response.BlockcypherResponse -import com.tangem.blockchain.blockchains.bitcoin.network.response.BlockcypherTx import retrofit2.http.* interface BlockcypherApi { diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/BlockcypherProvider.kt b/blockchain/src/main/java/com/tangem/blockchain/network/blockcypher/BlockcypherProvider.kt similarity index 66% rename from blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/BlockcypherProvider.kt rename to blockchain/src/main/java/com/tangem/blockchain/network/blockcypher/BlockcypherProvider.kt index 58b6bec6a4..857e06f449 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/BlockcypherProvider.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/network/blockcypher/BlockcypherProvider.kt @@ -1,30 +1,35 @@ -package com.tangem.blockchain.blockchains.bitcoin.network +package com.tangem.blockchain.network.blockcypher import com.tangem.blockchain.blockchains.bitcoin.BitcoinUnspentOutput -import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockcypherApi -import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockcypherBody -import com.tangem.blockchain.blockchains.bitcoin.network.response.BlockcypherFee -import com.tangem.blockchain.blockchains.bitcoin.network.response.BlockcypherResponse +import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinAddressResponse +import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinFee +import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinProvider +import com.tangem.blockchain.network.blockcypher.BlockcypherApi +import com.tangem.blockchain.network.blockcypher.BlockcypherBody import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.extensions.Result import com.tangem.blockchain.extensions.SimpleResult import com.tangem.blockchain.extensions.retryIO import com.tangem.common.extensions.hexToBytes -class BlockcypherProvider(private val api: BlockcypherApi, isTestNet: Boolean) : BitcoinProvider { +class BlockcypherProvider(private val api: BlockcypherApi, blockchain: Blockchain) : BitcoinProvider { - private val blockchain = "btc" - private val decimals = Blockchain.Bitcoin.decimals() - - private val network = if (isTestNet) { - BlockcypherNetwork.Test.network - } else { - BlockcypherNetwork.Main.network + private val blockchainPath = when (blockchain) { + Blockchain.Bitcoin, Blockchain.BitcoinTestnet -> "btc" + Blockchain.Litecoin -> "ltc" + else -> throw Exception("${blockchain.fullName} blockchain is not supported by ${this::class.simpleName}") } + private val network = when (blockchain) { + Blockchain.BitcoinTestnet -> "test3" + else -> "main" + } + + private val decimals = blockchain.decimals() + override suspend fun getInfo(address: String): Result { try { - val addressData: BlockcypherResponse = retryIO { api.getAddressData(blockchain, network, address) } + val addressData: BlockcypherResponse = retryIO { api.getAddressData(blockchainPath, network, address) } val unspents = addressData.txrefs?.map { BitcoinUnspentOutput( it.amount!!.toBigDecimal().movePointLeft(decimals), @@ -45,7 +50,7 @@ class BlockcypherProvider(private val api: BlockcypherApi, isTestNet: Boolean) : override suspend fun getFee(): Result { return try { - val receivedFee: BlockcypherFee = retryIO { api.getFee(blockchain, network) } + val receivedFee: BlockcypherFee = retryIO { api.getFee(blockchainPath, network) } Result.Success( BitcoinFee(receivedFee.minFeePerKb!!.toBigDecimal().movePointLeft(decimals), receivedFee.normalFeePerKb!!.toBigDecimal().movePointLeft(decimals), @@ -60,7 +65,7 @@ class BlockcypherProvider(private val api: BlockcypherApi, isTestNet: Boolean) : return try { retryIO { api.sendTransaction( - blockchain, network, BlockcypherBody(transaction), BlockcypherToken.getToken()) + blockchainPath, network, BlockcypherBody(transaction), BlockcypherToken.getToken()) } SimpleResult.Success } catch (error: Exception) { @@ -76,9 +81,4 @@ private object BlockcypherToken { "66a8a37c5e9d4d2c9bb191acfe7f93aa") fun getToken(): String = tokens.random() -} - -private enum class BlockcypherNetwork(val network: String) { - Main("main"), - Test("test3") } \ No newline at end of file diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/response/BlockcypherResponse.kt b/blockchain/src/main/java/com/tangem/blockchain/network/blockcypher/BlockcypherResponse.kt similarity index 95% rename from blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/response/BlockcypherResponse.kt rename to blockchain/src/main/java/com/tangem/blockchain/network/blockcypher/BlockcypherResponse.kt index a0e79c45b2..71dec770fe 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/network/response/BlockcypherResponse.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/network/blockcypher/BlockcypherResponse.kt @@ -1,4 +1,4 @@ -package com.tangem.blockchain.blockchains.bitcoin.network.response +package com.tangem.blockchain.network.blockcypher import com.squareup.moshi.Json import com.squareup.moshi.JsonClass From 07b92b401d0caab159122d188c2e28947d3f7c87 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 14 May 2020 15:28:36 +0300 Subject: [PATCH 2/2] Updated on 2026-08-14 --- .../blockchains/bitcoin/BitcoinAddressTest.kt | 3 +- .../litecoin/LitecoinAddressTest.kt | 28 +++++++++++++++++++ .../common/WalletManagerFactoryTest.kt | 12 ++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 blockchain/src/test/java/com/tangem/blockchain/blockchains/litecoin/LitecoinAddressTest.kt diff --git a/blockchain/src/test/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinAddressTest.kt b/blockchain/src/test/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinAddressTest.kt index c8b7cca7ef..9fabb12561 100644 --- a/blockchain/src/test/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinAddressTest.kt +++ b/blockchain/src/test/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinAddressTest.kt @@ -1,12 +1,13 @@ package com.tangem.blockchain.blockchains.bitcoin import com.google.common.truth.Truth +import com.tangem.blockchain.common.Blockchain import com.tangem.common.extensions.hexToBytes import org.junit.Test class BitcoinAddressTest { - private val addressService = BitcoinAddressService() + private val addressService = BitcoinAddressService(Blockchain.Bitcoin) @Test fun makeAddressFromCorrectPublicKey() { diff --git a/blockchain/src/test/java/com/tangem/blockchain/blockchains/litecoin/LitecoinAddressTest.kt b/blockchain/src/test/java/com/tangem/blockchain/blockchains/litecoin/LitecoinAddressTest.kt new file mode 100644 index 0000000000..a8753d94a4 --- /dev/null +++ b/blockchain/src/test/java/com/tangem/blockchain/blockchains/litecoin/LitecoinAddressTest.kt @@ -0,0 +1,28 @@ +package com.tangem.blockchain.blockchains.litecoin + +import com.google.common.truth.Truth +import com.tangem.blockchain.blockchains.bitcoin.BitcoinAddressService +import com.tangem.blockchain.common.Blockchain +import com.tangem.common.extensions.hexToBytes +import org.junit.Test + +class LitecoinAddressTest { + + private val addressService = BitcoinAddressService(Blockchain.Litecoin) + + @Test + fun makeAddressFromCorrectPublicKey() { + val walletPublicKey = "044A76C9A70422160F515F956D0F50C71BBBA4F9862A22913817D63F0B1EF7C2FAF512E1C91B1BE827560EFE24FB1652B47337E296C778DFB1014D080CDD35EF65".hexToBytes() + val expected = "LeweDi2SMmishGyCqQN2972qNByaSRdcfT" + + Truth.assertThat(addressService.makeAddress(walletPublicKey)) + .isEqualTo(expected) + } + + @Test + fun validateCorrectAddress() { + val address = "LeweDi2SMmishGyCqQN2972qNByaSRdcfT" + Truth.assertThat(addressService.validate(address)) + .isTrue() + } +} \ No newline at end of file diff --git a/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt b/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt index ff9edbcdd1..fc6ced7192 100644 --- a/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt +++ b/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt @@ -7,6 +7,7 @@ import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager import com.tangem.blockchain.blockchains.bitcoincash.BitcoinCashWalletManager import com.tangem.blockchain.blockchains.cardano.CardanoWalletManager import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager +import com.tangem.blockchain.blockchains.litecoin.LitecoinWalletManager import com.tangem.blockchain.blockchains.stellar.StellarWalletManager import com.tangem.blockchain.blockchains.xrp.XrpWalletManager import com.tangem.commands.ReadCommand @@ -92,4 +93,15 @@ internal class WalletManagerFactoryTest { Truth.assertThat(walletManager) .isInstanceOf(BitcoinCashWalletManager::class.java) } + + @Test + fun createLitecoinWalletManager() { + val data = "0108BB00000000000023200754414E47454D00020102800A322E3432642053444B000341043539F86A40ADD04CE165764A761FD3E4D251028615D2A573B1C3AE652E60AFDBFAF02E3239E89EF2C43FA448A327557ADC5AF36376A0574570F6DBD20113514A0A04041E76310C618102FFFF8A0101820407E40414830B54414E47454D2053444B0084034C5443864004BDEAD0117544886346CB47F7CA84ABA8C34239502F23D28595A4B16CAD72F7DE506BA818B86A649C2BB945986D4574993B3B755B47CBEE31C4FB931F6748183041045F16BD1D2EAFE463E62A335A09E6B2BBCBD04452526885CB679FC4D27AF1BD22F553C7DEEFB54FD3D4F361D14E6DC3F11B7D4EA183250A60720EBDF9E110CD26050A736563703235366B31000804000186A00701006041044A76C9A70422160F515F956D0F50C71BBBA4F9862A22913817D63F0B1EF7C2FAF512E1C91B1BE827560EFE24FB1652B47337E296C778DFB1014D080CDD35EF6562040001869D6304000000030F01009000" + val responseApdu = ResponseApdu(data.hexToBytes()) + val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu) + val walletManager = WalletManagerFactory.makeWalletManager(card!!) + + Truth.assertThat(walletManager) + .isInstanceOf(LitecoinWalletManager::class.java) + } } \ No newline at end of file