Updated on 2026-08-14
This commit is contained in:
commit
5105528ddc
18 changed files with 54 additions and 64 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -85,10 +85,6 @@ class BitcoinNetworkManager(private val isTestNet: Boolean) : BitcoinProvider {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val SATOSHI_IN_BTC = 100000000.toBigDecimal()
|
||||
}
|
||||
}
|
||||
|
||||
data class BitcoinAddressResponse(
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
|
@ -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>?
|
||||
}
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
ext.versions = [
|
||||
kotlin : '1.3.72',
|
||||
build_gradle: '3.6.2',
|
||||
build_gradle: '3.6.3',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.common.extensions
|
||||
|
||||
import java.math.BigDecimal
|
||||
|
||||
fun BigDecimal.isZero() : Boolean {
|
||||
return this.compareTo(BigDecimal.ZERO) == 0
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue