Updated on 2026-08-14

This commit is contained in:
Tangem 2020-04-21 15:52:25 +00:00
commit 5105528ddc
18 changed files with 54 additions and 64 deletions

View file

@ -78,18 +78,18 @@ class BlockchainDemoActivity : AppCompatActivity() {
walletManager.update()
withContext(Dispatchers.Main) {
binding.tvBalance.text =
"${walletManager.wallet.balances[AmountType.Coin]?.value
"${walletManager.wallet.balances[AmountType.Coin]?.value?.toPlainString()
?: "error"} ${walletManager.blockchain.currency}"
val token = walletManager.wallet.balances[AmountType.Token]
if (token != null) {
binding.tvBalance.text = token.currencySymbol + " " + token.value
binding.tvBalance.text = token.value?.toPlainString() + " " + token.currencySymbol
binding.etSumToSend.text = Editable.Factory.getInstance().newEditable(
token.value.toString()
token.value?.toPlainString() ?: ""
)
} else {
binding.etSumToSend.text =
Editable.Factory.getInstance().newEditable(
walletManager.wallet.balances[AmountType.Coin]?.value.toString()
walletManager.wallet.balances[AmountType.Coin]?.value?.toPlainString()
)
}
binding.btnCheckFee.isEnabled = true

View file

@ -23,10 +23,6 @@ class BinanceWalletManager(
private val transactionBuilder = BinanceTransactionBuilder(walletPublicKey, isTestNet)
private val networkManager = BinanceNetworkManager(isTestNet)
init {
wallet.balances[AmountType.Coin] = Amount(null, blockchain, address)
}
override suspend fun update() {
val result = networkManager.getInfo(address)
when (result) {

View file

@ -2,6 +2,7 @@ package com.tangem.blockchain.bitcoin
import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.common.extensions.Result
import com.tangem.common.extensions.isZero
import org.bitcoinj.core.*
import org.bitcoinj.crypto.TransactionSignature
import org.bitcoinj.script.Script
@ -81,7 +82,7 @@ internal fun TransactionData.toBitcoinJTransaction(networkParameters: NetworkPar
transaction.addOutput(
Coin.parseCoin(this.amount.value!!.toPlainString()),
Address.fromString(networkParameters, this.destinationAddress))
if (change != 0.toBigDecimal()) {
if (!change.isZero()) {
transaction.addOutput(
Coin.parseCoin(change.toPlainString()),
Address.fromString(networkParameters,

View file

@ -3,7 +3,6 @@ package com.tangem.blockchain.bitcoin
import android.util.Log
import com.tangem.blockchain.bitcoin.network.BitcoinAddressResponse
import com.tangem.blockchain.bitcoin.network.BitcoinNetworkManager
import com.tangem.blockchain.bitcoin.network.BitcoinNetworkManager.Companion.SATOSHI_IN_BTC
import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.extensions.Result
import com.tangem.blockchain.common.extensions.SimpleResult
@ -26,10 +25,6 @@ class BitcoinWalletManager(
private val transactionBuilder = BitcoinTransactionBuilder(isTestNet)
private val networkManager = BitcoinNetworkManager(isTestNet)
init {
wallet.balances[AmountType.Coin] = Amount(null, blockchain)
}
override suspend fun update() {
val response = networkManager.getInfo(address)
when (response) {
@ -80,9 +75,11 @@ class BitcoinWalletManager(
when (val result = networkManager.getFee()) {
is Result.Failure -> return result
is Result.Success -> {
val feeValue = BigDecimal.ONE.movePointLeft(blockchain.decimals.toInt())
amount.value = amount.value!! - feeValue
val sizeResult = transactionBuilder.getEstimateSize(
TransactionData(amount,
Amount(1.toBigDecimal().divide(SATOSHI_IN_BTC), blockchain),
Amount(feeValue, blockchain),
address, destination),
walletPublicKey
)

View file

@ -85,10 +85,6 @@ class BitcoinNetworkManager(private val isTestNet: Boolean) : BitcoinProvider {
}
}
}
companion object {
val SATOSHI_IN_BTC = 100000000.toBigDecimal()
}
}
data class BitcoinAddressResponse(

View file

@ -1,9 +1,9 @@
package com.tangem.blockchain.bitcoin.network
import com.tangem.blockchain.bitcoin.UnspentTransaction
import com.tangem.blockchain.bitcoin.network.BitcoinNetworkManager.Companion.SATOSHI_IN_BTC
import com.tangem.blockchain.bitcoin.network.api.BlockchainInfoApi
import com.tangem.blockchain.bitcoin.network.api.EstimatefeeApi
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.extensions.Result
import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain.common.extensions.retryIO
@ -16,6 +16,7 @@ class BlockchainInfoProvider(
private val blockchainApi: BlockchainInfoApi,
private val estimatefeeApi: EstimatefeeApi
) : BitcoinProvider {
val decimals = Blockchain.Bitcoin.decimals.toInt()
override suspend fun getInfo(address: String): Result<BitcoinAddressResponse> {
return try {
@ -29,7 +30,7 @@ class BlockchainInfoProvider(
val bitcoinUnspents = unspents.unspentOutputs.map {
UnspentTransaction(
it.amount!!.toBigDecimal().divide(SATOSHI_IN_BTC),
it.amount!!.toBigDecimal().movePointLeft(decimals),
it.outputIndex!!.toLong(),
it.hash!!.hexToBytes(),
it.outputScript!!.hexToBytes())
@ -37,7 +38,7 @@ class BlockchainInfoProvider(
Result.Success(
BitcoinAddressResponse(
addressData.finalBalance?.toBigDecimal()?.divide(SATOSHI_IN_BTC)
addressData.finalBalance?.toBigDecimal()?.movePointLeft(decimals)
?: 0.toBigDecimal(), unconfirmedTransactions, bitcoinUnspents))
}
} catch (exception: Exception) {

View file

@ -1,11 +1,11 @@
package com.tangem.blockchain.bitcoin.network
import com.tangem.blockchain.bitcoin.UnspentTransaction
import com.tangem.blockchain.bitcoin.network.BitcoinNetworkManager.Companion.SATOSHI_IN_BTC
import com.tangem.blockchain.bitcoin.network.api.BlockcypherApi
import com.tangem.blockchain.bitcoin.network.api.BlockcypherBody
import com.tangem.blockchain.bitcoin.network.response.BlockcypherFee
import com.tangem.blockchain.bitcoin.network.response.BlockcypherResponse
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.extensions.Result
import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain.common.extensions.retryIO
@ -14,6 +14,7 @@ import com.tangem.common.extensions.hexToBytes
class BlockcypherProvider(private val api: BlockcypherApi, isTestNet: Boolean) : BitcoinProvider {
private val blockchain = "btc"
private val decimals = Blockchain.Bitcoin.decimals.toInt()
private val network = if (isTestNet) {
BlockcypherNetwork.Test.network
@ -26,14 +27,14 @@ class BlockcypherProvider(private val api: BlockcypherApi, isTestNet: Boolean) :
val addressData: BlockcypherResponse = retryIO { api.getAddressData(blockchain, network, address) }
val unspents = addressData.txrefs?.map {
UnspentTransaction(
it.amount!!.toBigDecimal().divide(SATOSHI_IN_BTC),
it.amount!!.toBigDecimal().movePointLeft(decimals),
it.outputIndex!!.toLong(),
it.hash!!.hexToBytes(),
it.outputScript!!.hexToBytes()
)
}
return Result.Success(BitcoinAddressResponse(
addressData.balance!!.toBigDecimal().divide(SATOSHI_IN_BTC),
addressData.balance!!.toBigDecimal().movePointLeft(decimals),
addressData.unconfirmedBalance != 0L,
unspents))
@ -43,27 +44,27 @@ class BlockcypherProvider(private val api: BlockcypherApi, isTestNet: Boolean) :
}
override suspend fun getFee(): Result<BitcoinFee> {
try {
return try {
val receivedFee: BlockcypherFee = retryIO { api.getFee(blockchain, network) }
return Result.Success(
BitcoinFee(receivedFee.minFeePerKb!!.toBigDecimal().divide(SATOSHI_IN_BTC),
receivedFee.normalFeePerKb!!.toBigDecimal().divide(SATOSHI_IN_BTC),
receivedFee.priorityFeePerKb!!.toBigDecimal().divide(SATOSHI_IN_BTC))
Result.Success(
BitcoinFee(receivedFee.minFeePerKb!!.toBigDecimal().movePointLeft(decimals),
receivedFee.normalFeePerKb!!.toBigDecimal().movePointLeft(decimals),
receivedFee.priorityFeePerKb!!.toBigDecimal().movePointLeft(decimals))
)
} catch (error: Exception) {
return Result.Failure(error)
Result.Failure(error)
}
}
override suspend fun sendTransaction(transaction: String): SimpleResult {
try {
return try {
retryIO {
api.sendTransaction(
blockchain, network, BlockcypherBody(transaction), BlockcypherToken.getToken())
}
return SimpleResult.Success
SimpleResult.Success
} catch (error: Exception) {
return SimpleResult.Failure(error)
SimpleResult.Failure(error)
}
}
}

View file

@ -68,8 +68,8 @@ class CardanoAddressFactory {
.end()
.build())
val hexAddress = addressBaos.toByteArray()
return hexAddress.encodeBase58()
val addressBytes = addressBaos.toByteArray()
return addressBytes.encodeBase58()
}
fun extendPublicKey(publicKey: ByteArray): ByteArray {

View file

@ -9,6 +9,7 @@ import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain.common.extensions.encodeBase64NoWrap
import com.tangem.blockchain.wallets.CurrencyWallet
import com.tangem.common.CompletionResult
import java.math.RoundingMode
class CardanoWalletManager(
private val cardId: String,
@ -61,7 +62,7 @@ class CardanoWalletManager(
val size = transactionBuilder.getEstimateSize(
TransactionData(amount, null, address, destination), walletPublicKey
)
val fee = (a + b * size).toBigDecimal()
val fee = (a + b * size).toBigDecimal().setScale(blockchain.decimals.toInt(), RoundingMode.UP)
return Result.Success(listOf(Amount(blockchain.currency, fee, address, blockchain.decimals)))
}
}

View file

@ -12,9 +12,9 @@ interface AdaliteApi {
@Headers("Content-Type: application/json")
@POST("/api/bulk/addresses/utxo")
suspend fun getUnspents(@Body address: String): AdaliteUnspents
suspend fun getUnspents(@Body addresses: List<String>): AdaliteUnspents
@Headers("Content-Type: application/json")
@POST("/api/v2/txs/signed")
suspend fun sendTransaction(@Body adaliteBody: AdaliteSendBody): ResponseBody // List<Any>?
suspend fun sendTransaction(@Body adaliteBody: AdaliteSendBody): String // List<Any>?
}

View file

@ -1,11 +1,13 @@
package com.tangem.blockchain.cardano.network.adalite
import com.squareup.moshi.Json
import com.tangem.blockchain.cardano.network.CardanoAddressResponse
import com.tangem.blockchain.cardano.UnspentOutput
import com.tangem.blockchain.cardano.network.api.AdaliteApi
import com.tangem.blockchain.common.extensions.Result
import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain.common.extensions.retryIO
import com.tangem.common.extensions.hexToBytes
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
@ -15,7 +17,7 @@ class AdaliteProvider(private val api: AdaliteApi) {
return try {
coroutineScope {
val addressDeferred = retryIO { async { api.getAddress(address) } }
val unspentsDeferred = retryIO { async { api.getUnspents(address) } }
val unspentsDeferred = retryIO { async { api.getUnspents(listOf(address)) } }
val addressData = addressDeferred.await()
val unspents = unspentsDeferred.await()
@ -24,7 +26,7 @@ class AdaliteProvider(private val api: AdaliteApi) {
UnspentOutput(
it.amountData!!.amount!!,
it.outputIndex!!.toLong(),
it.hash!!.toByteArray()
it.hash!!.hexToBytes()
)
}
@ -42,7 +44,7 @@ class AdaliteProvider(private val api: AdaliteApi) {
suspend fun sendTransaction(transaction: String): SimpleResult {
return try {
retryIO { api.sendTransaction(AdaliteSendBody(transaction)) }
val response = retryIO { api.sendTransaction(AdaliteSendBody(transaction)) }
SimpleResult.Success
} catch (exception: Exception) {
SimpleResult.Failure(exception)
@ -50,4 +52,7 @@ class AdaliteProvider(private val api: AdaliteApi) {
}
}
data class AdaliteSendBody(val signedTransaction: String)
data class AdaliteSendBody(
@Json(name = "signedTx")
val signedTransaction: String
)

View file

@ -5,7 +5,7 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class AdaliteAddress(
@Json(name = "final_balance")
@Json(name = "Right")
var data: AdaliteAddressData? = null
)

View file

@ -49,7 +49,7 @@ const val API_STELLAR = "https://horizon.stellar.org/"
const val API_STELLAR_RESERVE = "https://horizon.sui.li/"
const val API_STELLAR_TESTNET = "https://horizon-testnet.stellar.org/"
const val API_BLOCKCHAIN_INFO = "https://blockchain.info/"
const val API_ADALITE = "https://explorer2.adalite.io"
const val API_ADALITE = "https://explorer3.adalite.io"
const val API_ADALITE_RESERVE = "https://nodes.southeastasia.cloudapp.azure.com"
const val API_RIPPLED = "https://s1.ripple.com:51234"
const val API_RIPPLED_RESERVE = "https://s2.ripple.com:51234"

View file

@ -37,17 +37,6 @@ class EthereumWalletManager(
private var pendingTxCount = -1L
private var txCount = -1L
init {
if (token != null) wallet.balances[AmountType.Token] =
Amount(
token.symbol,
null,
token.contractAddress,
token.decimals,
AmountType.Token)
wallet.balances[AmountType.Coin] = Amount(null, blockchain)
}
override suspend fun update() {
val result = networkManager.getInfo(address, wallet.balances[AmountType.Token]?.address)
when (result) {

View file

@ -12,6 +12,7 @@ import kotlinx.coroutines.coroutineScope
import org.kethereum.ETH_IN_WEI
import java.math.BigDecimal
import java.math.BigInteger
import java.math.RoundingMode
class EthereumNetworkManager {
@ -70,8 +71,8 @@ class EthereumNetworkManager {
private fun String.parseFee(gasLimit: Long): List<BigDecimal> {
val gasPrice = this.responseToNumber().toBigDecimal()
val minFee = gasPrice.multiply(gasLimit.toBigDecimal())
val normalFee = minFee.multiply(BigDecimal(1.2))
val priorityFee = minFee.multiply(BigDecimal(1.5))
val normalFee = minFee.multiply(BigDecimal(1.2)).setScale(0, RoundingMode.HALF_UP)
val priorityFee = minFee.multiply(BigDecimal(1.5)).setScale(0, RoundingMode.HALF_UP)
return listOf(
minFee.convertFeeToEth(),
normalFee.convertFeeToEth(),

View file

@ -22,11 +22,6 @@ class XrpWalletManager(
private val transactionBuilder = XrpTransactionBuilder(walletPublicKey)
private val networkManager = XrpNetworkManager()
init {
wallet.balances[AmountType.Coin] = Amount(null, blockchain)
wallet.balances[AmountType.Reserve] = Amount(null, blockchain, type = AmountType.Reserve)
}
override suspend fun update() {
val result = networkManager.getInfo(address)
when (result) {

View file

@ -1,4 +1,4 @@
ext.versions = [
kotlin : '1.3.72',
build_gradle: '3.6.2',
build_gradle: '3.6.3',
]

View file

@ -0,0 +1,7 @@
package com.tangem.common.extensions
import java.math.BigDecimal
fun BigDecimal.isZero() : Boolean {
return this.compareTo(BigDecimal.ZERO) == 0
}