diff --git a/app/src/main/java/io/horizontalsystems/bitcoinkit/demo/BalanceFragment.kt b/app/src/main/java/io/horizontalsystems/bitcoinkit/demo/BalanceFragment.kt index 3fac4efd..cbe0f98a 100644 --- a/app/src/main/java/io/horizontalsystems/bitcoinkit/demo/BalanceFragment.kt +++ b/app/src/main/java/io/horizontalsystems/bitcoinkit/demo/BalanceFragment.kt @@ -41,7 +41,7 @@ class BalanceFragment : Fragment() { } else -> { balanceValue.text = NumberFormatHelper.cryptoAmountFormat.format(balance.spendable / 100_000_000.0) - balanceUnspendableValue.text = NumberFormatHelper.cryptoAmountFormat.format(balance.unspendable / 100_000_000.0) + balanceUnspendableValue.text = NumberFormatHelper.cryptoAmountFormat.format((balance.unspendableTimeLocked + balance.unspendableNotRelayed) / 100_000_000.0) } } }) diff --git a/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/BitcoinCoreBuilder.kt b/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/BitcoinCoreBuilder.kt index da4ee20c..141baaaa 100644 --- a/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/BitcoinCoreBuilder.kt +++ b/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/BitcoinCoreBuilder.kt @@ -491,7 +491,7 @@ class BitcoinCoreBuilder { val signer = TransactionSigner(ecdsaInputSigner, schnorrInputSigner) transactionCreator = TransactionCreator(transactionBuilder, pendingTransactionProcessor, transactionSenderInstance, signer, bloomFilterManager) replacementTransactionBuilder = ReplacementTransactionBuilder( - storage, transactionSizeCalculator, dustCalculator, metadataExtractor, pluginManager, unspentOutputProvider, publicKeyManager, conflictsResolver + storage, transactionSizeCalculator, dustCalculator, metadataExtractor, pluginManager, unspentOutputProvider, publicKeyManager, conflictsResolver, lockTimeSetter ) } diff --git a/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/managers/UnspentOutputProvider.kt b/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/managers/UnspentOutputProvider.kt index a3d0e3ac..81e63953 100644 --- a/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/managers/UnspentOutputProvider.kt +++ b/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/managers/UnspentOutputProvider.kt @@ -18,17 +18,20 @@ class UnspentOutputProvider( } } - private fun getUnspendableUtxo(): List { - return allUtxo().filter { - !pluginManager.isSpendable(it) || it.transaction.status != Transaction.Status.RELAYED - } + private fun getUnspendableTimeLockedUtxo() = allUtxo().filter { + !pluginManager.isSpendable(it) + } + + private fun getUnspendableNotRelayedUtxo() = allUtxo().filter { + it.transaction.status != Transaction.Status.RELAYED } fun getBalance(): BalanceInfo { val spendable = getSpendableUtxo().sumOf { it.output.value } - val unspendable = getUnspendableUtxo().sumOf { it.output.value } + val unspendableTimeLocked = getUnspendableTimeLockedUtxo().sumOf { it.output.value } + val unspendableNotRelayed = getUnspendableNotRelayedUtxo().sumOf { it.output.value } - return BalanceInfo(spendable, unspendable) + return BalanceInfo(spendable, unspendableTimeLocked, unspendableNotRelayed) } // Only confirmed spendable outputs diff --git a/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/models/TransactionInfo.kt b/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/models/TransactionInfo.kt index 6b4c014f..3bea1fd6 100644 --- a/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/models/TransactionInfo.kt +++ b/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/models/TransactionInfo.kt @@ -187,4 +187,4 @@ data class BlockInfo( val timestamp: Long ) -data class BalanceInfo(val spendable: Long, val unspendable: Long) +data class BalanceInfo(val spendable: Long, val unspendableTimeLocked: Long, val unspendableNotRelayed: Long) diff --git a/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/rbf/ReplacementTransactionBuilder.kt b/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/rbf/ReplacementTransactionBuilder.kt index 4cca8a22..d12fcbe2 100644 --- a/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/rbf/ReplacementTransactionBuilder.kt +++ b/bitcoincore/src/main/kotlin/io/horizontalsystems/bitcoincore/rbf/ReplacementTransactionBuilder.kt @@ -19,6 +19,7 @@ import io.horizontalsystems.bitcoincore.storage.InputWithPreviousOutput import io.horizontalsystems.bitcoincore.storage.UnspentOutput import io.horizontalsystems.bitcoincore.transactions.TransactionConflictsResolver import io.horizontalsystems.bitcoincore.transactions.TransactionSizeCalculator +import io.horizontalsystems.bitcoincore.transactions.builder.LockTimeSetter import io.horizontalsystems.bitcoincore.transactions.builder.MutableTransaction import io.horizontalsystems.bitcoincore.transactions.extractors.TransactionMetadataExtractor import io.horizontalsystems.bitcoincore.utils.ShuffleSorter @@ -32,7 +33,8 @@ class ReplacementTransactionBuilder( private val pluginManager: PluginManager, private val unspentOutputProvider: UnspentOutputProvider, private val publicKeyManager: IPublicKeyManager, - private val conflictsResolver: TransactionConflictsResolver + private val conflictsResolver: TransactionConflictsResolver, + private val lockTimeSetter: LockTimeSetter ) { private fun replacementTransaction( @@ -181,6 +183,7 @@ class ReplacementTransactionBuilder( mutableTransaction = mutableTransaction, outputs = fixedOutputs + outputs ) + lockTimeSetter.setLockTime(mutableTransaction) mutableTransaction } } @@ -382,9 +385,13 @@ class ReplacementTransactionBuilder( } val confirmedUtxoTotalValue = unspentOutputProvider.getConfirmedSpendableUtxo().sumOf { it.output.value } - val feeRange = LongRange(absoluteFee, originalFee + removableOutputsValue + confirmedUtxoTotalValue) + val maxFeeAmount = originalFee + removableOutputsValue + confirmedUtxoTotalValue - return ReplacementTransactionInfo(replacementTxMinSize, feeRange) + return if (absoluteFee > maxFeeAmount) { + null + } else { + ReplacementTransactionInfo(replacementTxMinSize, LongRange(absoluteFee, maxFeeAmount)) + } } sealed class BuildError : Throwable() {