From 9c7a2f3ab132c55cdd0ff9ce597523015da9ae78 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 21 May 2020 21:43:55 +0300 Subject: [PATCH 1/2] Updated on 2026-08-14 --- .../bitcoin/BitcoinAddressService.kt | 8 ++- .../bitcoin/BitcoinTransactionBuilder.kt | 4 +- .../bitcoin/BitcoinWalletManager.kt | 2 +- .../ducatus/DucatusMainNetParams.java | 69 +++++++++++++++++++ .../ducatus/DucatusWalletManager.kt | 40 +++++++++++ .../ducatus/network/DucatusNetworkManager.kt | 8 +++ .../ducatus/network/bitcore/BitcoreApi.kt | 21 ++++++ .../network/bitcore/BitcoreProvider.kt | 64 +++++++++++++++++ .../network/bitcore/BitcoreResponse.kt | 34 +++++++++ .../tangem/blockchain/common/Blockchain.kt | 10 +-- .../blockchain/common/WalletManagerFactory.kt | 10 ++- .../blockchain/network/RetrofitBuilder.kt | 3 +- 12 files changed, 263 insertions(+), 10 deletions(-) create mode 100644 blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusMainNetParams.java create mode 100644 blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusWalletManager.kt create mode 100644 blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/DucatusNetworkManager.kt create mode 100644 blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreApi.kt create mode 100644 blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreProvider.kt create mode 100644 blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreResponse.kt 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 1483284942..c3b5102b95 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,15 +1,18 @@ package com.tangem.blockchain.blockchains.bitcoin +import com.tangem.blockchain.blockchains.ducatus.DucatusMainNetParams 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.* +import org.bitcoinj.core.Base58 +import org.bitcoinj.core.LegacyAddress +import org.bitcoinj.core.NetworkParameters +import org.bitcoinj.core.SegwitAddress import org.bitcoinj.params.MainNetParams import org.bitcoinj.params.TestNet3Params -import java.security.MessageDigest class BitcoinAddressService(private val blockchain: Blockchain) : AddressService { @@ -17,6 +20,7 @@ class BitcoinAddressService(private val blockchain: Blockchain) : AddressService Blockchain.Bitcoin -> MainNetParams() Blockchain.BitcoinTestnet -> TestNet3Params() Blockchain.Litecoin -> LitecoinMainNetParams() + Blockchain.Ducatus -> DucatusMainNetParams() else -> throw Exception("${blockchain.fullName} blockchain is not supported by ${this::class.simpleName}") } 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 ede62d31a4..b829572b6f 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,5 +1,6 @@ package com.tangem.blockchain.blockchains.bitcoin +import com.tangem.blockchain.blockchains.ducatus.DucatusMainNetParams import com.tangem.blockchain.blockchains.litecoin.LitecoinMainNetParams import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.TransactionData @@ -23,6 +24,7 @@ open class BitcoinTransactionBuilder( Blockchain.Bitcoin, Blockchain.BitcoinCash -> MainNetParams() Blockchain.BitcoinTestnet -> TestNet3Params() Blockchain.Litecoin -> LitecoinMainNetParams() + Blockchain.Ducatus -> DucatusMainNetParams() else -> throw Exception("${blockchain.fullName} blockchain is not supported by ${this::class.simpleName}") } var unspentOutputs: List? = null @@ -64,7 +66,7 @@ open class BitcoinTransactionBuilder( } fun calculateChange(transactionData: TransactionData, unspentOutputs: List): BigDecimal { - val fullAmount = unspentOutputs!!.map { it.amount }.reduce { acc, number -> acc + number } + val fullAmount = unspentOutputs.map { it.amount }.reduce { acc, number -> acc + number } return fullAmount - (transactionData.amount.value!! + (transactionData.fee?.value ?: 0.toBigDecimal())) } 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 2a723fe5f9..ac393ef37e 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 @@ -13,7 +13,7 @@ import java.math.BigDecimal open class BitcoinWalletManager( cardId: String, wallet: Wallet, - private val transactionBuilder: BitcoinTransactionBuilder, + protected val transactionBuilder: BitcoinTransactionBuilder, private val networkManager: BitcoinProvider ) : WalletManager(cardId, wallet), TransactionSender { diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusMainNetParams.java b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusMainNetParams.java new file mode 100644 index 0000000000..c4373b88df --- /dev/null +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusMainNetParams.java @@ -0,0 +1,69 @@ +package com.tangem.blockchain.blockchains.ducatus; + +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 DucatusMainNetParams 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 DucatusMainNetParams() { + super(); + id = "org.bitcoinj.ducatus_mainnet"; + // Genesis hash is 12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2 + packetMagic = 0xfbc0b6db; + + maxTarget = Utils.decodeCompactBits(0x1e0fffffL); + port = 9333; + addressHeader = 49; + p2shHeader = 51; //TODO: is this right? Haven't seen Ducatus p2sh address ever + segwitAddressHrp = "duc"; //TODO: does Ducatus even have bech32 addresses? At least other blockchain's addresses won't pass + 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 DucatusMainNetParams instance; + + public static synchronized DucatusMainNetParams get() { + if (instance == null) { + instance = new DucatusMainNetParams(); + } + return instance; + } +} diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusWalletManager.kt new file mode 100644 index 0000000000..06ea687cb2 --- /dev/null +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusWalletManager.kt @@ -0,0 +1,40 @@ +package com.tangem.blockchain.blockchains.ducatus + +import com.tangem.blockchain.blockchains.bitcoin.BitcoinTransactionBuilder +import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager +import com.tangem.blockchain.blockchains.ducatus.network.DucatusNetworkManager +import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.TransactionData +import com.tangem.blockchain.common.TransactionSender +import com.tangem.blockchain.common.Wallet +import com.tangem.blockchain.extensions.Result +import java.math.BigDecimal + +class DucatusWalletManager( + cardId: String, + wallet: Wallet, + transactionBuilder: BitcoinTransactionBuilder, + networkManager: DucatusNetworkManager +) : BitcoinWalletManager(cardId, wallet, transactionBuilder, networkManager), TransactionSender { + override suspend fun getFee(amount: Amount, destination: String): Result> { + val feeValue = BigDecimal.ONE.movePointLeft(blockchain.decimals()) + val sizeResult = transactionBuilder.getEstimateSize( + TransactionData(amount, Amount(amount, feeValue), wallet.address, destination) + ) + return when (sizeResult) { + is Result.Failure -> sizeResult + is Result.Success -> { + val transactionSize = sizeResult.data.toBigDecimal() + val minFee = BigDecimal.valueOf(0.00000089).multiply(transactionSize) + val normalFee = BigDecimal.valueOf(0.00000144).multiply(transactionSize) + val priorityFee = BigDecimal.valueOf(0.00000350).multiply(transactionSize) + val fees = listOf( + Amount(minFee, blockchain), + Amount(normalFee, blockchain), + Amount(priorityFee, blockchain) + ) + Result.Success(fees) + } + } + } +} \ No newline at end of file diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/DucatusNetworkManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/DucatusNetworkManager.kt new file mode 100644 index 0000000000..7b08f99b72 --- /dev/null +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/DucatusNetworkManager.kt @@ -0,0 +1,8 @@ +package com.tangem.blockchain.blockchains.ducatus.network + +import com.tangem.blockchain.blockchains.ducatus.network.bitcore.BitcoreApi +import com.tangem.blockchain.blockchains.ducatus.network.bitcore.BitcoreProvider +import com.tangem.blockchain.network.API_DUCATUS +import com.tangem.blockchain.network.createRetrofitInstance + +class DucatusNetworkManager() : BitcoreProvider(createRetrofitInstance(API_DUCATUS).create(BitcoreApi::class.java)) \ No newline at end of file diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreApi.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreApi.kt new file mode 100644 index 0000000000..be7214c1ef --- /dev/null +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreApi.kt @@ -0,0 +1,21 @@ +package com.tangem.blockchain.blockchains.ducatus.network.bitcore + +import com.squareup.moshi.JsonClass +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Path + +interface BitcoreApi { + @GET("api/DUC/mainnet/address/{address}/balance") + suspend fun getBalance(@Path("address") address: String): BitcoreBalance + + @GET("api/DUC/mainnet/address/{address}/?unspent=true") + suspend fun getUnspents(@Path("address") address: String): List + + @POST("api/DUC/mainnet/tx/send") + suspend fun sendTransaction(@Body body: BitcoreSendBody): BitcoreSendResponse +} + +@JsonClass(generateAdapter = true) +data class BitcoreSendBody(val rawTx: List) \ No newline at end of file diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreProvider.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreProvider.kt new file mode 100644 index 0000000000..39fb7fa213 --- /dev/null +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreProvider.kt @@ -0,0 +1,64 @@ +package com.tangem.blockchain.blockchains.ducatus.network.bitcore + +import com.tangem.blockchain.blockchains.bitcoin.BitcoinUnspentOutput +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 +import com.tangem.blockchain.extensions.retryIO +import com.tangem.common.extensions.hexToBytes +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope + +open class BitcoreProvider(private val api: BitcoreApi) : BitcoinProvider{ + private val decimals = Blockchain.Ducatus.decimals() + + override suspend fun getInfo(address: String): Result { + return try { + coroutineScope { + val balanceDeferred = retryIO { async { api.getBalance(address) } } + val unspentsDeferred = retryIO { async { api.getUnspents(address) } } + + val balanceData = balanceDeferred.await() + val unspents = unspentsDeferred.await() + + val unspentTransactions = unspents.map { + BitcoinUnspentOutput( + amount = it.amount!!.toBigDecimal().movePointLeft(decimals), + outputIndex = it.index!!.toLong(), + transactionHash = it.transactionHash!!.hexToBytes(), + outputScript = it.script!!.hexToBytes() + ) + } + + Result.Success(BitcoinAddressResponse( + balance = balanceData.confirmed!!.toBigDecimal().movePointLeft(decimals),//only confirmed balance is returned right + hasUnconfirmed = balanceData.unconfirmed != null, + unspentOutputs = unspentTransactions + )) + } + } catch (error: Exception) { + Result.Failure(error) + } + } + + override suspend fun getFee(): Result { + TODO("Not yet implemented")// bitcore is used only in ducatus and fee is hardcoded there + } + + + override suspend fun sendTransaction(transaction: String): SimpleResult { + return try { + val response = retryIO { api.sendTransaction(BitcoreSendBody(listOf(transaction))) } + if (response.txid != null) { + SimpleResult.Success + } else { + SimpleResult.Failure(Exception("Unknown send transaction error")) + } + } catch (error: Exception) { + SimpleResult.Failure(error) + } + } +} \ No newline at end of file diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreResponse.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreResponse.kt new file mode 100644 index 0000000000..5b7cda90db --- /dev/null +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreResponse.kt @@ -0,0 +1,34 @@ +package com.tangem.blockchain.blockchains.ducatus.network.bitcore + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class BitcoreBalance( + @Json(name = "confirmed") + var confirmed: Long? = null, + + @Json(name = "unconfirmed") + var unconfirmed: Long? = null +) + +@JsonClass(generateAdapter = true) +data class BitcoreUtxo( + @Json(name = "mintTxid") + var transactionHash: String? = null, + + @Json(name = "mintIndex") + var index: Int? = null, + + @Json(name = "value") + var amount: Long? = null, + + @Json(name = "script") + var script: String? = null +) + +@JsonClass(generateAdapter = true) +data class BitcoreSendResponse( + @Json(name = "txid") + var txid: String? = null +) \ 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 d7ba034407..f732d9d723 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/common/Blockchain.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/common/Blockchain.kt @@ -19,6 +19,7 @@ enum class Blockchain( BitcoinTestnet("BTC/test", "BTCt", "Bitcoin Testnet"), BitcoinCash("BCH", "BCH", "Bitcoin Cash"), Litecoin("LTC", "LTC", "Litecoin"), + Ducatus("DUC", "DUC", "Ducatus"), Ethereum("ETH", "ETH", "Ethereum"), RSK("RSK", "RBTC", "RSK"), Cardano("CARDANO", "ADA", "Cardano"), @@ -29,7 +30,7 @@ enum class Blockchain( Tezos("TEZOS", "XTZ", "Tezos"); fun decimals(): Int = when (this) { - Bitcoin, BitcoinTestnet, BitcoinCash, Binance, BinanceTestnet, Litecoin -> 8 + Bitcoin, BitcoinTestnet, BitcoinCash, Binance, BinanceTestnet, Litecoin, Ducatus -> 8 Cardano, XRP, Tezos -> 6 Ethereum, RSK -> 18 Stellar -> 7 @@ -45,8 +46,7 @@ enum class Blockchain( fun validateAddress(address: String): Boolean = getAddressService().validate(address) private fun getAddressService(): AddressService = when (this) { - Unknown -> throw Exception("unsupported blockchain") - Bitcoin, BitcoinTestnet, Litecoin -> BitcoinAddressService(this) + Bitcoin, BitcoinTestnet, Litecoin, Ducatus -> BitcoinAddressService(this) BitcoinCash -> BitcoinCashAddressService() Ethereum, RSK -> EthereumAddressService() Cardano -> CardanoAddressService() @@ -55,6 +55,7 @@ enum class Blockchain( BinanceTestnet -> BinanceAddressService(true) Stellar -> StellarAddressService() Tezos -> TezosAddressService() + Unknown -> throw Exception("unsupported blockchain") } fun getShareUri(address: String): String = when (this) { @@ -71,9 +72,10 @@ enum class Blockchain( 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" + Ducatus -> "https://insight.ducatus.io/#/DUC/mainnet/address/$address" Cardano -> "https://cardanoexplorer.com/address/$address" Ethereum -> if (token == null) { - "https://etherscan.io/address/" + "https://etherscan.io/address/$address" } else { "https://etherscan.io/token/${token.contractAddress}?a=$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 1c7af4e354..c47a0b1f86 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/common/WalletManagerFactory.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/common/WalletManagerFactory.kt @@ -12,6 +12,8 @@ import com.tangem.blockchain.blockchains.bitcoincash.BitcoinCashWalletManager import com.tangem.blockchain.blockchains.cardano.CardanoTransactionBuilder import com.tangem.blockchain.blockchains.cardano.CardanoWalletManager import com.tangem.blockchain.blockchains.cardano.network.CardanoNetworkManager +import com.tangem.blockchain.blockchains.ducatus.DucatusWalletManager +import com.tangem.blockchain.blockchains.ducatus.network.DucatusNetworkManager import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionBuilder import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager import com.tangem.blockchain.blockchains.ethereum.network.EthereumNetworkManager @@ -19,7 +21,6 @@ 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 - import com.tangem.blockchain.blockchains.stellar.StellarWalletManager import com.tangem.blockchain.blockchains.tezos.TezosTransactionBuilder import com.tangem.blockchain.blockchains.tezos.TezosWalletManager @@ -72,6 +73,13 @@ object WalletManagerFactory { LitecoinNetworkManager() ) } + Blockchain.Ducatus -> { + return DucatusWalletManager( + cardId, wallet, + BitcoinTransactionBuilder(walletPublicKey, blockchain), + DucatusNetworkManager() + ) + } Blockchain.Ethereum, Blockchain.RSK -> { return EthereumWalletManager( cardId, wallet, diff --git a/blockchain/src/main/java/com/tangem/blockchain/network/RetrofitBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/network/RetrofitBuilder.kt index 8573dff8a7..97e13c5643 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/network/RetrofitBuilder.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/network/RetrofitBuilder.kt @@ -55,4 +55,5 @@ const val API_RIPPLED = "https://s1.ripple.com:51234/" const val API_RIPPLED_RESERVE = "https://s2.ripple.com:51234/" const val API_BLOCKCHAIR = "https://api.blockchair.com/" const val API_TEZOS = "https://teznode.letzbake.com" -const val API_TEZOS_RESERVE = "https://mainnet.tezrpc.me" \ No newline at end of file +const val API_TEZOS_RESERVE = "https://mainnet.tezrpc.me" +const val API_DUCATUS = "https://ducapi.rocknblock.io/" \ No newline at end of file From 77cd7c78ee5aba5db0f185699bbb382fc26f6d1b Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 22 May 2020 13:56:17 +0300 Subject: [PATCH 2/2] Updated on 2026-08-14 --- .../bitcoin/BitcoinAddressService.kt | 1 + .../blockchains/ducatus/DucatusAddressTest.kt | 28 +++++++++++++++++++ .../common/WalletManagerFactoryTest.kt | 14 +++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 blockchain/src/test/java/com/tangem/blockchain/blockchains/ducatus/DucatusAddressTest.kt 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 c3b5102b95..d05657d6ed 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 @@ -56,6 +56,7 @@ class BitcoinAddressService(private val blockchain: Blockchain) : AddressService Blockchain.Bitcoin -> LegacyAddress.fromBase58(MainNetParams(), address) Blockchain.BitcoinTestnet -> LegacyAddress.fromBase58(TestNet3Params(), address) Blockchain.Litecoin -> LegacyAddress.fromBase58(LitecoinMainNetParams(), address) + Blockchain.Ducatus -> LegacyAddress.fromBase58(DucatusMainNetParams(), address) else -> return false } true diff --git a/blockchain/src/test/java/com/tangem/blockchain/blockchains/ducatus/DucatusAddressTest.kt b/blockchain/src/test/java/com/tangem/blockchain/blockchains/ducatus/DucatusAddressTest.kt new file mode 100644 index 0000000000..528a0a199b --- /dev/null +++ b/blockchain/src/test/java/com/tangem/blockchain/blockchains/ducatus/DucatusAddressTest.kt @@ -0,0 +1,28 @@ +package com.tangem.blockchain.blockchains.ducatus + +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 DucatusAddressTest { + + private val addressService = BitcoinAddressService(Blockchain.Ducatus) + + @Test + fun makeAddressFromCorrectPublicKey() { + val walletPublicKey = "0485D520C8B907F0BC5E03FCBBAC212CCD270764BBFF4990A28653A2FB0D656C342DF143C4D52C43582289E20A81D5D014C1384A1FFFEA1D121903AD7ED35A01EA".hexToBytes() + val expected = "Ly3SZetcgr5gkZMwiNwVrts2z2r3jYieAG" + + Truth.assertThat(addressService.makeAddress(walletPublicKey)) + .isEqualTo(expected) + } + + @Test + fun validateCorrectAddress() { + val address = "Ly3SZetcgr5gkZMwiNwVrts2z2r3jYieAG" + 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 33c6e97c89..e372153248 100644 --- a/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt +++ b/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt @@ -6,6 +6,7 @@ import com.tangem.blockchain.blockchains.binance.BinanceWalletManager 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.ducatus.DucatusWalletManager import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager import com.tangem.blockchain.blockchains.litecoin.LitecoinWalletManager import com.tangem.blockchain.blockchains.stellar.StellarWalletManager @@ -107,7 +108,7 @@ internal class WalletManagerFactoryTest { } @Test - fun createLTezosWalletManager() { + fun createTezosWalletManager() { val data = "0108BB00000000000080200754414E47454D00020102800A322E3432642053444B0003410436CFC5D0A11353AE6AFEEDC84A2D02B2635C044DEEE47F99913072B8D166D14E557230AC5FB5272F1A0E523332CCE1A744B51DB53102FF7D3FDE023DC3477C460A04041E76310C638102FFFF8A0101820407E40514830B54414E47454D2053444B00840554455A4F538640C752685B29333CFB0DB0A7347579A0AE763F2B5C4BB09FD68E0B81A06CD01EC51347001732815A3ECFFCD78DDE4E53877581B9E4914B069570629D0C40A771B93041045F16BD1D2EAFE463E62A335A09E6B2BBCBD04452526885CB679FC4D27AF1BD22F553C7DEEFB54FD3D4F361D14E6DC3F11B7D4EA183250A60720EBDF9E110CD26050865643235353139000804000186A0070100602098E0E504F3A5FDE704400302ABB0A2EFB0DF0F95C166C91D7F207DEDCE10CBA362040001869F6304000000010F01009000" val responseApdu = ResponseApdu(data.hexToBytes()) val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu) @@ -116,4 +117,15 @@ internal class WalletManagerFactoryTest { Truth.assertThat(walletManager) .isInstanceOf(TezosWalletManager::class.java) } + + @Test + fun createDucatusWalletManager() { + val data = "0108BB00000000000098200754414E47454D00020102800A322E3432642053444B000341041B5FD7C590938E836B388B996AE451FDED54F625FF2CF05E26E5AADF6F690AEF125E3D0F23CB6B8D1F78040DF6F71B40D098F2D8BE504DDEE2E1F99BEADD90500A04041E76310C618102FFFF8A0101820407E40515830B54414E47454D2053444B00840344554386401B453C10A092A3448FA83CAFD4FC3D7EB5EA1BBBDD6A020CAAC8CED36BB2661F41EF0B0C7418214F670DFE1200DCE18597158119BEF6CC52A4FF3B7E021A53B93041045F16BD1D2EAFE463E62A335A09E6B2BBCBD04452526885CB679FC4D27AF1BD22F553C7DEEFB54FD3D4F361D14E6DC3F11B7D4EA183250A60720EBDF9E110CD26050A736563703235366B31000804000186A007010060410485D520C8B907F0BC5E03FCBBAC212CCD270764BBFF4990A28653A2FB0D656C342DF143C4D52C43582289E20A81D5D014C1384A1FFFEA1D121903AD7ED35A01EA62040001869D6304000000030F01009000" + val responseApdu = ResponseApdu(data.hexToBytes()) + val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu) + val walletManager = WalletManagerFactory.makeWalletManager(card) + + Truth.assertThat(walletManager) + .isInstanceOf(DucatusWalletManager::class.java) + } } \ No newline at end of file