Iterate on the Send demo.
Allow input. Allow multiple sends. Handle errors. Demonstrate an improved user experience where sending is disabled at the appropriate times.
This commit is contained in:
parent
93d4114848
commit
652e862d5c
|
@ -2,19 +2,18 @@ package cash.z.wallet.sdk.demoapp.demos.send
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.TextView
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import cash.z.wallet.sdk.Initializer
|
import cash.z.wallet.sdk.Initializer
|
||||||
import cash.z.wallet.sdk.Synchronizer
|
import cash.z.wallet.sdk.Synchronizer
|
||||||
import cash.z.wallet.sdk.block.CompactBlockProcessor
|
import cash.z.wallet.sdk.block.CompactBlockProcessor
|
||||||
import cash.z.wallet.sdk.demoapp.App
|
import cash.z.wallet.sdk.demoapp.App
|
||||||
import cash.z.wallet.sdk.demoapp.BaseDemoFragment
|
import cash.z.wallet.sdk.demoapp.BaseDemoFragment
|
||||||
|
import cash.z.wallet.sdk.demoapp.R
|
||||||
import cash.z.wallet.sdk.demoapp.databinding.FragmentSendBinding
|
import cash.z.wallet.sdk.demoapp.databinding.FragmentSendBinding
|
||||||
import cash.z.wallet.sdk.demoapp.util.SampleStorageBridge
|
import cash.z.wallet.sdk.demoapp.util.SampleStorageBridge
|
||||||
import cash.z.wallet.sdk.entity.*
|
import cash.z.wallet.sdk.entity.*
|
||||||
import cash.z.wallet.sdk.ext.*
|
import cash.z.wallet.sdk.ext.*
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class SendFragment : BaseDemoFragment<FragmentSendBinding>() {
|
class SendFragment : BaseDemoFragment<FragmentSendBinding>() {
|
||||||
private val config = App.instance.defaultConfig
|
private val config = App.instance.defaultConfig
|
||||||
|
@ -23,6 +22,36 @@ class SendFragment : BaseDemoFragment<FragmentSendBinding>() {
|
||||||
private lateinit var synchronizer: Synchronizer
|
private lateinit var synchronizer: Synchronizer
|
||||||
private lateinit var keyManager: SampleStorageBridge
|
private lateinit var keyManager: SampleStorageBridge
|
||||||
|
|
||||||
|
private lateinit var amountInput: TextView
|
||||||
|
private lateinit var addressInput: TextView
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Observable properties (done without livedata or flows for simplicity)
|
||||||
|
//
|
||||||
|
|
||||||
|
private var availableBalance = -1L
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
onUpdateSendButton()
|
||||||
|
}
|
||||||
|
private var isSending = false
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
if (value) Twig.sprout("Sending") else Twig.clip("Sending")
|
||||||
|
onUpdateSendButton()
|
||||||
|
}
|
||||||
|
private var isSyncing = true
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
onUpdateSendButton()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// BaseDemoFragment overrides
|
||||||
|
//
|
||||||
|
|
||||||
override fun inflateBinding(layoutInflater: LayoutInflater): FragmentSendBinding =
|
override fun inflateBinding(layoutInflater: LayoutInflater): FragmentSendBinding =
|
||||||
FragmentSendBinding.inflate(layoutInflater)
|
FragmentSendBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
@ -32,13 +61,30 @@ class SendFragment : BaseDemoFragment<FragmentSendBinding>() {
|
||||||
synchronizer = Synchronizer(App.instance, config.host, initializer.rustBackend)
|
synchronizer = Synchronizer(App.instance, config.host, initializer.rustBackend)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// STARTING POINT
|
||||||
override fun onResetComplete() {
|
override fun onResetComplete() {
|
||||||
initSendUI()
|
initSendUi()
|
||||||
startSynchronizer()
|
startSynchronizer()
|
||||||
monitorStatus()
|
monitorChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initSendUI() {
|
override fun onClear() {
|
||||||
|
synchronizer.stop()
|
||||||
|
initializer.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Private functions
|
||||||
|
//
|
||||||
|
|
||||||
|
private fun initSendUi() {
|
||||||
|
amountInput = binding.root.findViewById<TextView>(R.id.input_amount).apply {
|
||||||
|
text = config.sendAmount.toString()
|
||||||
|
}
|
||||||
|
addressInput = binding.root.findViewById<TextView>(R.id.input_address).apply {
|
||||||
|
text = config.toAddress
|
||||||
|
}
|
||||||
binding.buttonSend.setOnClickListener(::onSend)
|
binding.buttonSend.setOnClickListener(::onSend)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +94,7 @@ class SendFragment : BaseDemoFragment<FragmentSendBinding>() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun monitorStatus() {
|
private fun monitorChanges() {
|
||||||
synchronizer.status.collectWith(lifecycleScope, ::onStatus)
|
synchronizer.status.collectWith(lifecycleScope, ::onStatus)
|
||||||
synchronizer.progress.collectWith(lifecycleScope, ::onProgress)
|
synchronizer.progress.collectWith(lifecycleScope, ::onProgress)
|
||||||
synchronizer.balances.collectWith(lifecycleScope, ::onBalance)
|
synchronizer.balances.collectWith(lifecycleScope, ::onBalance)
|
||||||
|
@ -56,11 +102,12 @@ class SendFragment : BaseDemoFragment<FragmentSendBinding>() {
|
||||||
|
|
||||||
private fun onStatus(status: Synchronizer.Status) {
|
private fun onStatus(status: Synchronizer.Status) {
|
||||||
binding.textStatus.text = "Status: $status"
|
binding.textStatus.text = "Status: $status"
|
||||||
}
|
if (status == Synchronizer.Status.SYNCING) {
|
||||||
|
isSyncing = true
|
||||||
override fun onClear() {
|
binding.textBalance.text = "Calculating balance..."
|
||||||
synchronizer.stop()
|
} else {
|
||||||
initializer.clear()
|
isSyncing = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onProgress(i: Int) {
|
private fun onProgress(i: Int) {
|
||||||
|
@ -69,39 +116,69 @@ class SendFragment : BaseDemoFragment<FragmentSendBinding>() {
|
||||||
else -> "Downloading blocks...$i%"
|
else -> "Downloading blocks...$i%"
|
||||||
}
|
}
|
||||||
binding.textStatus.text = message
|
binding.textStatus.text = message
|
||||||
|
binding.textBalance.text = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onBalance(balance: CompactBlockProcessor.WalletBalance) {
|
private fun onBalance(balance: CompactBlockProcessor.WalletBalance) {
|
||||||
binding.textBalances.text = """
|
availableBalance = balance.available
|
||||||
|
binding.textBalance.text = """
|
||||||
Available balance: ${balance.available.convertZatoshiToZecString()}
|
Available balance: ${balance.available.convertZatoshiToZecString()}
|
||||||
Total balance: ${balance.total.convertZatoshiToZecString()}
|
Total balance: ${balance.total.convertZatoshiToZecString()}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
binding.buttonSend.isEnabled = balance.available > 0
|
|
||||||
binding.textStatus.text = "Synced!"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onSend(unused: View) {
|
private fun onSend(unused: View) {
|
||||||
// TODO: add input fields to the UI. Possibly, including a scanner for the address input
|
isSending = true
|
||||||
|
val amount = amountInput.text.toString().toDouble().convertZecToZatoshi()
|
||||||
|
val toAddress = addressInput.text.toString()
|
||||||
synchronizer.sendToAddress(
|
synchronizer.sendToAddress(
|
||||||
keyManager.key,
|
keyManager.key,
|
||||||
0.0024.toZec().convertZecToZatoshi(),
|
amount,
|
||||||
config.toAddress,
|
toAddress,
|
||||||
"Demo App Funds"
|
"Demo App Funds"
|
||||||
).collectWith(lifecycleScope, ::onPendingTxUpdated)
|
).collectWith(lifecycleScope, ::onPendingTxUpdated)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onPendingTxUpdated(pendingTransaction: PendingTransaction?) {
|
private fun onPendingTxUpdated(pendingTransaction: PendingTransaction?) {
|
||||||
|
val id = pendingTransaction?.id ?: -1
|
||||||
val message = when {
|
val message = when {
|
||||||
pendingTransaction == null -> "Transaction not found"
|
pendingTransaction == null -> "Transaction not found"
|
||||||
pendingTransaction.isMined() -> "Transaction Mined!"
|
pendingTransaction.isMined() -> "Transaction Mined (id: $id)!\n\nSEND COMPLETE".also { isSending = false }
|
||||||
pendingTransaction.isSubmitted() -> "Successfully submitted transaction!"
|
pendingTransaction.isSubmitSuccess() -> "Successfully submitted transaction!\nAwaiting confirmation..."
|
||||||
pendingTransaction.isFailedEncoding() -> "ERROR: failed to encode transaction!"
|
pendingTransaction.isFailedEncoding() -> "ERROR: failed to encode transaction! (id: $id)".also { isSending = false }
|
||||||
pendingTransaction.isFailedSubmit() -> "ERROR: failed to submit transaction!"
|
pendingTransaction.isFailedSubmit() -> "ERROR: failed to submit transaction! (id: $id)".also { isSending = false }
|
||||||
pendingTransaction.isCreated() -> "Transaction creation complete!"
|
pendingTransaction.isCreated() -> "Transaction creation complete! (id: $id)"
|
||||||
pendingTransaction.isCreating() -> "Creating transaction!"
|
pendingTransaction.isCreating() -> "Creating transaction!".also { onResetInfo() }
|
||||||
else -> "Transaction updated!".also { twig("Unhandled TX state: $pendingTransaction") }
|
else -> "Transaction updated!".also { twig("Unhandled TX state: $pendingTransaction") }
|
||||||
}
|
}
|
||||||
twig("PENDING TX: $message")
|
twig("Pending TX Updated: $message")
|
||||||
Toast.makeText(App.instance, message, Toast.LENGTH_SHORT).show()
|
binding.textInfo.apply {
|
||||||
|
text = "$text\n$message"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onUpdateSendButton() {
|
||||||
|
with(binding.buttonSend) {
|
||||||
|
when {
|
||||||
|
isSending -> {
|
||||||
|
text = "➡ sending"
|
||||||
|
isEnabled = false
|
||||||
|
}
|
||||||
|
isSyncing -> {
|
||||||
|
text = "⌛ syncing"
|
||||||
|
isEnabled = false
|
||||||
|
}
|
||||||
|
availableBalance <= 0 -> isEnabled = false
|
||||||
|
else -> {
|
||||||
|
text = "send"
|
||||||
|
isEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onResetInfo() {
|
||||||
|
binding.textInfo.text = "Active Transaction:"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
@ -15,14 +14,32 @@
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_bias="0.2">
|
app:layout_constraintVertical_bias="0.05">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/text_block_height"
|
android:id="@+id/input_amount"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:ems="8"
|
android:ems="8"
|
||||||
android:hint="amount"
|
android:hint="zec amount"
|
||||||
|
android:inputType="number"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/text_layout_address"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/text_layout_amount"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/text_layout_amount">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_address"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ems="8"
|
||||||
|
android:hint="to address"
|
||||||
android:inputType="number"
|
android:inputType="number"
|
||||||
android:textSize="20sp" />
|
android:textSize="20sp" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
@ -46,14 +63,30 @@
|
||||||
android:layout_marginTop="32dp"
|
android:layout_marginTop="32dp"
|
||||||
android:text="Initializing wallet..."
|
android:text="Initializing wallet..."
|
||||||
app:layout_constraintStart_toStartOf="@id/text_layout_amount"
|
app:layout_constraintStart_toStartOf="@id/text_layout_amount"
|
||||||
app:layout_constraintTop_toBottomOf="@id/text_layout_amount" />
|
app:layout_constraintTop_toBottomOf="@id/text_layout_address" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/text_balances"
|
android:id="@+id/text_balance"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
app:layout_constraintStart_toStartOf="@id/text_status"
|
app:layout_constraintStart_toStartOf="@id/text_status"
|
||||||
app:layout_constraintTop_toBottomOf="@id/text_status"
|
app:layout_constraintTop_toBottomOf="@id/text_status" />
|
||||||
android:text="Available balance: --\nTotal balance: --" />
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/text_balance"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/text_balance"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_info"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingBottom="48dp"/>
|
||||||
|
</ScrollView>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,7 +1,6 @@
|
||||||
package cash.z.wallet.sdk
|
package cash.z.wallet.sdk
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.paging.PagedList
|
|
||||||
import cash.z.wallet.sdk.Synchronizer.Status.*
|
import cash.z.wallet.sdk.Synchronizer.Status.*
|
||||||
import cash.z.wallet.sdk.block.CompactBlockDbStore
|
import cash.z.wallet.sdk.block.CompactBlockDbStore
|
||||||
import cash.z.wallet.sdk.block.CompactBlockDownloader
|
import cash.z.wallet.sdk.block.CompactBlockDownloader
|
||||||
|
@ -254,16 +253,19 @@ class SdkSynchronizer internal constructor(
|
||||||
// TODO: this would be the place to clear out any stale pending transactions. Remove filter
|
// TODO: this would be the place to clear out any stale pending transactions. Remove filter
|
||||||
// logic and then delete any pending transaction with sufficient confirmations (all in one
|
// logic and then delete any pending transaction with sufficient confirmations (all in one
|
||||||
// db transaction).
|
// db transaction).
|
||||||
manager.getAll().first().filter { !it.isMined() }.forEach { pendingTx ->
|
manager.getAll().first().filter { it.isSubmitSuccess() && !it.isMined() }
|
||||||
twig("checking for updates on pendingTx id: ${pendingTx.id}")
|
.forEach { pendingTx ->
|
||||||
pendingTx.rawTransactionId?.let { rawId ->
|
twig("checking for updates on pendingTx id: ${pendingTx.id}")
|
||||||
ledger.findMinedHeight(rawId)?.let { minedHeight ->
|
pendingTx.rawTransactionId?.let { rawId ->
|
||||||
twig("found matching transaction for pending transaction with id" +
|
ledger.findMinedHeight(rawId)?.let { minedHeight ->
|
||||||
" ${pendingTx.id} mined at height ${minedHeight}!")
|
twig(
|
||||||
manager.applyMinedHeight(pendingTx, minedHeight)
|
"found matching transaction for pending transaction with id" +
|
||||||
|
" ${pendingTx.id} mined at height ${minedHeight}!"
|
||||||
|
)
|
||||||
|
manager.applyMinedHeight(pendingTx, minedHeight)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -287,13 +289,15 @@ class SdkSynchronizer internal constructor(
|
||||||
manager.initSpend(zatoshi, toAddress, memo, fromAccountIndex).let { placeHolderTx ->
|
manager.initSpend(zatoshi, toAddress, memo, fromAccountIndex).let { placeHolderTx ->
|
||||||
emit(placeHolderTx)
|
emit(placeHolderTx)
|
||||||
manager.encode(spendingKey, placeHolderTx).let { encodedTx ->
|
manager.encode(spendingKey, placeHolderTx).let { encodedTx ->
|
||||||
manager.submit(encodedTx)
|
if (!encodedTx.isFailedEncoding() && !encodedTx.isCancelled()) {
|
||||||
|
manager.submit(encodedTx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.flatMapLatest {
|
}.flatMapLatest {
|
||||||
twig("Monitoring pending transaction for updates...")
|
twig("Monitoring pending transaction (id: ${it.id}) for updates...")
|
||||||
manager.monitorById(it.id)
|
manager.monitorById(it.id)
|
||||||
}
|
}.distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,15 @@ inline fun Double?.toZec(decimals: Int = ZEC_FORMATTER.maximumFractionDigits): B
|
||||||
return BigDecimal(this?.toString() ?: "0.0", MathContext.DECIMAL128).setScale(decimals, ZEC_FORMATTER.roundingMode)
|
return BigDecimal(this?.toString() ?: "0.0", MathContext.DECIMAL128).setScale(decimals, ZEC_FORMATTER.roundingMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a Double Zec value as a Long Zatoshi value, by first converting to Zec with the given
|
||||||
|
* precision.
|
||||||
|
* Start with Zec -> End with Zatoshi.
|
||||||
|
*/
|
||||||
|
inline fun Double?.convertZecToZatoshi(decimals: Int = ZEC_FORMATTER.maximumFractionDigits): Long {
|
||||||
|
return this.toZec(decimals).convertZecToZatoshi()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format a BigDecimal Zec value as a BigDecimal Zec value, right-padded to the given number of fraction digits.
|
* Format a BigDecimal Zec value as a BigDecimal Zec value, right-padded to the given number of fraction digits.
|
||||||
* Start with Zec -> End with Zec.
|
* Start with Zec -> End with Zec.
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package cash.z.wallet.sdk.transaction
|
package cash.z.wallet.sdk.transaction
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.lifecycle.LifecycleOwner
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import cash.z.wallet.sdk.db.PendingTransactionDao
|
import cash.z.wallet.sdk.db.PendingTransactionDao
|
||||||
|
@ -15,6 +13,7 @@ import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.lang.IllegalStateException
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -134,14 +133,14 @@ class PersistentTransactionManager(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun submit(pendingTx: PendingTransaction): PendingTransaction = withContext(Dispatchers.IO) {
|
override suspend fun submit(pendingTx: PendingTransaction): PendingTransaction = withContext(Dispatchers.IO) {
|
||||||
var tx1 = pendingTransactionDao { findById(pendingTx.id) }
|
// reload the tx to check for cancellation
|
||||||
if(tx1 == null) twig("unable to find transaction for id: ${pendingTx.id}")
|
var storedTx = pendingTransactionDao { findById(pendingTx.id) } ?: throw IllegalStateException("Error while submitting transaction. No pending transaction found that matches the one being submitted. Verify that the transaction still exists among the set of pending transactions.")
|
||||||
var tx = tx1!!
|
var tx = storedTx
|
||||||
try {
|
try {
|
||||||
// do nothing when cancelled
|
// do nothing when cancelled
|
||||||
if (!tx.isCancelled()) {
|
if (!tx.isCancelled()) {
|
||||||
twig("submitting transaction to lightwalletd - memo: ${tx.memo} amount: ${tx.value}")
|
twig("submitting transaction to lightwalletd - memo: ${tx.memo} amount: ${tx.value}")
|
||||||
val response = service.submitTransaction(tx.raw!!)
|
val response = service.submitTransaction(tx.raw)
|
||||||
val error = response.errorCode < 0
|
val error = response.errorCode < 0
|
||||||
twig("${if (error) "FAILURE! " else "SUCCESS!"} submit transaction completed with response: ${response.errorCode}: ${response.errorMessage}")
|
twig("${if (error) "FAILURE! " else "SUCCESS!"} submit transaction completed with response: ${response.errorCode}: ${response.errorMessage}")
|
||||||
tx = tx.copy(
|
tx = tx.copy(
|
||||||
|
|
Loading…
Reference in New Issue