Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memo #656

Merged
merged 2 commits into from
Apr 11, 2024
Merged

Memo #656

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import io.horizontalsystems.bitcoincore.BitcoinCore.KitState
import io.horizontalsystems.bitcoincore.core.IPluginData
import io.horizontalsystems.bitcoincore.exceptions.AddressFormatException
import io.horizontalsystems.bitcoincore.managers.SendValueErrors
import io.horizontalsystems.bitcoincore.models.*
import io.horizontalsystems.bitcoincore.models.BalanceInfo
import io.horizontalsystems.bitcoincore.models.BitcoinSendInfo
import io.horizontalsystems.bitcoincore.models.BlockInfo
import io.horizontalsystems.bitcoincore.models.TransactionDataSortType
import io.horizontalsystems.bitcoincore.models.TransactionFilterType
import io.horizontalsystems.bitcoincore.models.TransactionInfo
import io.horizontalsystems.bitcoinkit.BitcoinKit
import io.horizontalsystems.hdwalletkit.HDWallet.Purpose
import io.horizontalsystems.hodler.HodlerData
Expand Down Expand Up @@ -156,6 +161,7 @@ class MainViewModel : ViewModel(), BitcoinKit.Listener {
try {
val transaction = bitcoinKit.send(
address!!,
null,
amount!!,
feeRate = feePriority.feeRate,
sortType = TransactionDataSortType.Shuffle,
Expand All @@ -182,7 +188,7 @@ class MainViewModel : ViewModel(), BitcoinKit.Listener {

fun onMaxClick() {
try {
amountLiveData.value = bitcoinKit.maximumSpendableValue(address, feePriority.feeRate, null, getPluginData())
amountLiveData.value = bitcoinKit.maximumSpendableValue(address, null, feePriority.feeRate, null, getPluginData())
} catch (e: Exception) {
amountLiveData.value = 0
errorLiveData.value = when (e) {
Expand All @@ -206,7 +212,7 @@ class MainViewModel : ViewModel(), BitcoinKit.Listener {
}

private fun fee(value: Long, address: String? = null): BitcoinSendInfo {
return bitcoinKit.sendInfo(value, address, feeRate = feePriority.feeRate, unspentOutputs = null, pluginData = getPluginData())
return bitcoinKit.sendInfo(value, address, null, feeRate = feePriority.feeRate, unspentOutputs = null, pluginData = getPluginData())
}

private fun getPluginData(): MutableMap<Byte, IPluginData> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import io.horizontalsystems.dashkit.models.DashTransactionInfo
import io.horizontalsystems.hodler.HodlerOutputData
import io.horizontalsystems.hodler.HodlerPlugin
import java.text.DateFormat
import java.util.*
import java.util.Date
import java.util.Locale

class TransactionsFragment : Fragment(), ViewHolderTransaction.Listener {

Expand Down Expand Up @@ -165,6 +166,7 @@ class ViewHolderTransaction(val containerView: View, private val listener: Liste
sb.append("\n value: ${it.value}")
sb.append("\n mine: ${it.mine}")
sb.append("\n change: ${it.changeOutput}")
sb.append("\n memo: ${it.memo}")

if (it.pluginId == HodlerPlugin.id && it.pluginData != null) {
(it.pluginData as? HodlerOutputData)?.let { hodlerData ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ abstract class AbstractKit {
fun sendInfo(
value: Long,
address: String? = null,
memo: String?,
senderPay: Boolean = true,
feeRate: Int,
unspentOutputs: List<UnspentOutputInfo>?,
Expand All @@ -79,6 +80,7 @@ abstract class AbstractKit {
return bitcoinCore.sendInfo(
value = value,
address = address,
memo = memo,
senderPay = senderPay,
feeRate = feeRate,
unspentOutputs = unspentOutputs,
Expand All @@ -88,6 +90,7 @@ abstract class AbstractKit {

fun send(
address: String,
memo: String?,
value: Long,
senderPay: Boolean = true,
feeRate: Int,
Expand All @@ -96,23 +99,25 @@ abstract class AbstractKit {
pluginData: Map<Byte, IPluginData> = mapOf(),
rbfEnabled: Boolean,
): FullTransaction {
return bitcoinCore.send(address, value, senderPay, feeRate, sortType, unspentOutputs, pluginData, rbfEnabled)
return bitcoinCore.send(address, memo, value, senderPay, feeRate, sortType, unspentOutputs, pluginData, rbfEnabled)
}

fun send(
address: String,
memo: String?,
value: Long,
senderPay: Boolean = true,
feeRate: Int,
sortType: TransactionDataSortType,
pluginData: Map<Byte, IPluginData> = mapOf(),
rbfEnabled: Boolean,
): FullTransaction {
return bitcoinCore.send(address, value, senderPay, feeRate, sortType, null, pluginData, rbfEnabled)
return bitcoinCore.send(address, memo, value, senderPay, feeRate, sortType, null, pluginData, rbfEnabled)
}

fun send(
hash: ByteArray,
memo: String?,
scriptType: ScriptType,
value: Long,
senderPay: Boolean = true,
Expand All @@ -121,23 +126,24 @@ abstract class AbstractKit {
unspentOutputs: List<UnspentOutputInfo>? = null,
rbfEnabled: Boolean,
): FullTransaction {
return bitcoinCore.send(hash, scriptType, value, senderPay, feeRate, sortType, unspentOutputs, rbfEnabled)
return bitcoinCore.send(hash, memo, scriptType, value, senderPay, feeRate, sortType, unspentOutputs, rbfEnabled)
}

fun send(
hash: ByteArray,
memo: String?,
scriptType: ScriptType,
value: Long,
senderPay: Boolean = true,
feeRate: Int,
sortType: TransactionDataSortType,
rbfEnabled: Boolean,
): FullTransaction {
return bitcoinCore.send(hash, scriptType, value, senderPay, feeRate, sortType, null, rbfEnabled)
return bitcoinCore.send(hash, memo, scriptType, value, senderPay, feeRate, sortType, null, rbfEnabled)
}

fun redeem(unspentOutput: UnspentOutput, address: String, feeRate: Int, sortType: TransactionDataSortType, rbfEnabled: Boolean): FullTransaction {
return bitcoinCore.redeem(unspentOutput, address, feeRate, sortType, rbfEnabled)
fun redeem(unspentOutput: UnspentOutput, address: String, memo: String?, feeRate: Int, sortType: TransactionDataSortType, rbfEnabled: Boolean): FullTransaction {
return bitcoinCore.redeem(unspentOutput, address, memo, feeRate, sortType, rbfEnabled)
}

fun receiveAddress(): String {
Expand Down Expand Up @@ -180,8 +186,8 @@ abstract class AbstractKit {
bitcoinCore.watchTransaction(filter, listener)
}

fun maximumSpendableValue(address: String?, feeRate: Int, unspentOutputs: List<UnspentOutputInfo>?, pluginData: Map<Byte, IPluginData>): Long {
return bitcoinCore.maximumSpendableValue(address, feeRate, unspentOutputs, pluginData)
fun maximumSpendableValue(address: String?, memo: String?, feeRate: Int, unspentOutputs: List<UnspentOutputInfo>?, pluginData: Map<Byte, IPluginData>): Long {
return bitcoinCore.maximumSpendableValue(address, memo, feeRate, unspentOutputs, pluginData)
}

fun minimumSpendableValue(address: String?): Int {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ class BitcoinCore(
fun sendInfo(
value: Long,
address: String? = null,
memo: String?,
senderPay: Boolean = true,
feeRate: Int,
unspentOutputs: List<UnspentOutputInfo>?,
Expand All @@ -202,13 +203,15 @@ class BitcoinCore(
feeRate = feeRate,
senderPay = senderPay,
toAddress = address,
memo = memo,
unspentOutputs = outputs,
pluginData = pluginData
) ?: throw CoreError.ReadOnlyCore
}

fun send(
address: String,
memo: String?,
value: Long,
senderPay: Boolean = true,
feeRate: Int,
Expand All @@ -224,6 +227,7 @@ class BitcoinCore(
}
return transactionCreator?.create(
toAddress = address,
memo = memo,
value = value,
feeRate = feeRate,
senderPay = senderPay,
Expand All @@ -236,6 +240,7 @@ class BitcoinCore(

fun send(
hash: ByteArray,
memo: String?,
scriptType: ScriptType,
value: Long,
senderPay: Boolean = true,
Expand All @@ -252,6 +257,7 @@ class BitcoinCore(
}
return transactionCreator?.create(
toAddress = address.stringValue,
memo = memo,
value = value,
feeRate = feeRate,
senderPay = senderPay,
Expand All @@ -262,8 +268,8 @@ class BitcoinCore(
) ?: throw CoreError.ReadOnlyCore
}

fun redeem(unspentOutput: UnspentOutput, address: String, feeRate: Int, sortType: TransactionDataSortType, rbfEnabled: Boolean): FullTransaction {
return transactionCreator?.create(unspentOutput, address, feeRate, sortType, rbfEnabled) ?: throw CoreError.ReadOnlyCore
fun redeem(unspentOutput: UnspentOutput, address: String, memo: String?, feeRate: Int, sortType: TransactionDataSortType, rbfEnabled: Boolean): FullTransaction {
return transactionCreator?.create(unspentOutput, address, memo, feeRate, sortType, rbfEnabled) ?: throw CoreError.ReadOnlyCore
}

fun receiveAddress(): String {
Expand Down Expand Up @@ -406,6 +412,7 @@ class BitcoinCore(

fun maximumSpendableValue(
address: String?,
memo: String?,
feeRate: Int,
unspentOutputs: List<UnspentOutputInfo>?,
pluginData: Map<Byte, IPluginData>
Expand All @@ -425,6 +432,7 @@ class BitcoinCore(
feeRate = feeRate,
senderPay = false,
toAddress = address,
memo = memo,
unspentOutputs = outputs,
pluginData = pluginData
).fee
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
package io.horizontalsystems.bitcoincore.core

import io.horizontalsystems.bitcoincore.extensions.toReversedHex
import io.horizontalsystems.bitcoincore.models.*
import io.horizontalsystems.bitcoincore.io.BitcoinInput
import io.horizontalsystems.bitcoincore.models.InvalidTransaction
import io.horizontalsystems.bitcoincore.models.Transaction
import io.horizontalsystems.bitcoincore.models.TransactionInfo
import io.horizontalsystems.bitcoincore.models.TransactionInputInfo
import io.horizontalsystems.bitcoincore.models.TransactionMetadata
import io.horizontalsystems.bitcoincore.models.TransactionOutput
import io.horizontalsystems.bitcoincore.models.TransactionOutputInfo
import io.horizontalsystems.bitcoincore.models.TransactionStatus
import io.horizontalsystems.bitcoincore.models.rbfEnabled
import io.horizontalsystems.bitcoincore.storage.FullTransactionInfo
import io.horizontalsystems.bitcoincore.transactions.scripts.ScriptType
import java.io.ByteArrayInputStream

class BaseTransactionInfoConverter(private val pluginManager: PluginManager) {

Expand Down Expand Up @@ -37,6 +48,7 @@ class BaseTransactionInfoConverter(private val pluginManager: PluginManager) {
changeOutput = output.changeOutput,
value = output.value,
address = output.address,
memo = parseMemo(output),
pluginId = output.pluginId,
pluginDataString = output.pluginData,
pluginData = pluginManager.parsePluginData(output, transaction.timestamp))
Expand All @@ -63,6 +75,16 @@ class BaseTransactionInfoConverter(private val pluginManager: PluginManager) {
)
}

private fun parseMemo(output: TransactionOutput): String? {
if (output.scriptType != ScriptType.NULL_DATA) return null
val payload = output.lockingScriptPayload ?: return null
if (payload.isEmpty()) return null

val input = BitcoinInput(ByteArrayInputStream(payload))
input.readByte() // op_return
return input.readString()
}

private fun getInvalidTransactionInfo(
transaction: InvalidTransaction,
metadata: TransactionMetadata
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ interface IRecipientSetter {
toAddress: String,
value: Long,
pluginData: Map<Byte, IPluginData>,
skipChecking: Boolean
skipChecking: Boolean,
memo: String?
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@ import io.horizontalsystems.bitcoincore.storage.UnspentOutput
import io.horizontalsystems.bitcoincore.transactions.scripts.ScriptType

interface IUnspentOutputSelector {
fun select(value: Long, feeRate: Int, outputScriptType: ScriptType = ScriptType.P2PKH, changeType: ScriptType = ScriptType.P2PKH, senderPay: Boolean, pluginDataOutputSize: Int): SelectedUnspentOutputInfo
fun select(
value: Long,
memo: String?,
feeRate: Int,
outputScriptType: ScriptType = ScriptType.P2PKH,
changeType: ScriptType = ScriptType.P2PKH,
senderPay: Boolean,
pluginDataOutputSize: Int
): SelectedUnspentOutputInfo
}

data class SelectedUnspentOutputInfo(
Expand All @@ -27,12 +35,28 @@ class UnspentOutputSelectorChain(private val unspentOutputProvider: IUnspentOutp
val all: List<UnspentOutput>
get() = unspentOutputProvider.getSpendableUtxo()

override fun select(value: Long, feeRate: Int, outputScriptType: ScriptType, changeType: ScriptType, senderPay: Boolean, pluginDataOutputSize: Int): SelectedUnspentOutputInfo {
override fun select(
value: Long,
memo: String?,
feeRate: Int,
outputScriptType: ScriptType,
changeType: ScriptType,
senderPay: Boolean,
pluginDataOutputSize: Int
): SelectedUnspentOutputInfo {
var lastError: SendValueErrors? = null

for (selector in concreteSelectors) {
try {
return selector.select(value, feeRate, outputScriptType, changeType, senderPay, pluginDataOutputSize)
return selector.select(
value,
memo,
feeRate,
outputScriptType,
changeType,
senderPay,
pluginDataOutputSize
)
} catch (e: SendValueErrors) {
lastError = e
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class UnspentOutputQueue(
sizeCalculator.transactionSize(
previousOutputs = selectedOutputs.map { it.output },
outputs = listOf(parameters.outputScriptType),
memo = parameters.memo,
pluginDataOutputSize = parameters.pluginDataOutputSize
) * parameters.fee

Expand All @@ -83,6 +84,7 @@ class UnspentOutputQueue(
data class Parameters(
val value: Long,
val senderPay: Boolean,
val memo: String?,
val fee: Int,
val outputsLimit: Int?,
val outputScriptType: ScriptType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class UnspentOutputSelector(
@Throws(SendValueErrors::class)
override fun select(
value: Long,
memo: String?,
feeRate: Int,
outputScriptType: ScriptType,
changeType: ScriptType,
Expand All @@ -39,6 +40,7 @@ class UnspentOutputSelector(
val params = UnspentOutputQueue.Parameters(
value = value,
senderPay = senderPay,
memo = memo,
fee = feeRate,
outputsLimit = outputsLimit,
outputScriptType = outputScriptType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class UnspentOutputSelectorSingleNoChange(

override fun select(
value: Long,
memo: String?,
feeRate: Int,
outputScriptType: ScriptType,
changeType: ScriptType,
Expand Down Expand Up @@ -42,6 +43,7 @@ class UnspentOutputSelectorSingleNoChange(
val params = UnspentOutputQueue.Parameters(
value = value,
senderPay = senderPay,
memo = memo,
fee = feeRate,
outputsLimit = null,
outputScriptType = outputScriptType,
Expand Down
Loading
Loading