use bsv::wallet::interfaces::AbortActionResult;
use crate::error::{WalletError, WalletResult};
use crate::signer::types::ValidAbortActionArgs;
use crate::status::TransactionStatus;
use crate::storage::find_args::{
FindOutputsArgs, FindTransactionsArgs, OutputPartial, TransactionPartial,
};
use crate::storage::manager::WalletStorageManager;
pub async fn signer_abort_action(
storage: &WalletStorageManager,
auth: &str,
args: &ValidAbortActionArgs,
) -> WalletResult<AbortActionResult> {
let (user, _) = storage.find_or_insert_user(auth).await?;
let user_id = user.user_id;
let find_tx_args = FindTransactionsArgs {
partial: TransactionPartial {
user_id: Some(user_id),
reference: Some(args.reference.clone()),
..Default::default()
},
..Default::default()
};
let txs = storage.find_transactions(&find_tx_args).await?;
let transaction = txs
.into_iter()
.next()
.ok_or_else(|| WalletError::InvalidParameter {
parameter: "reference".to_string(),
must_be: format!(
"a valid transaction reference. '{}' not found",
args.reference
),
})?;
if transaction.status != TransactionStatus::Unsigned
&& transaction.status != TransactionStatus::Unprocessed
{
return Err(WalletError::InvalidOperation(format!(
"Cannot abort transaction with status {}. Only unsigned or unprocessed transactions can be aborted.",
transaction.status
)));
}
let transaction_id = transaction.transaction_id;
let tx_update = TransactionPartial {
status: Some(TransactionStatus::Failed),
..Default::default()
};
storage
.update_transaction(transaction_id, &tx_update)
.await?;
let find_spent_args = FindOutputsArgs {
partial: OutputPartial {
user_id: Some(user_id),
spent_by: Some(transaction_id),
..Default::default()
},
..Default::default()
};
let spent_outputs = storage.find_outputs(&find_spent_args).await?;
for output in &spent_outputs {
if output.transaction_id != transaction_id {
let output_update = OutputPartial {
spendable: Some(true),
..Default::default()
};
storage
.update_output(output.output_id, &output_update)
.await?;
}
}
Ok(AbortActionResult { aborted: true })
}