| 486 | } |
| 487 | |
| 488 | void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked) |
| 489 | { |
| 490 | if(!model || !model->getOptionsModel()) |
| 491 | return; |
| 492 | |
| 493 | QString question_string, informative_text, detailed_text; |
| 494 | if (!PrepareSendText(question_string, informative_text, detailed_text)) return; |
| 495 | assert(m_current_transaction); |
| 496 | assert(!g_con_elementsmode || m_current_blind_details); |
| 497 | |
| 498 | const QString confirmation = tr("Confirm send coins"); |
| 499 | const bool enable_send{!model->wallet().privateKeysDisabled() || model->wallet().hasExternalSigner()}; |
| 500 | const bool always_show_unsigned{model->getOptionsModel()->getEnablePSBTControls()}; |
| 501 | auto confirmationDialog = new SendConfirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, enable_send, always_show_unsigned, this); |
| 502 | confirmationDialog->setAttribute(Qt::WA_DeleteOnClose); |
| 503 | // TODO: Replace QDialog::exec() with safer QDialog::show(). |
| 504 | const auto retval = static_cast<QMessageBox::StandardButton>(confirmationDialog->exec()); |
| 505 | |
| 506 | if(retval != QMessageBox::Yes && retval != QMessageBox::Save) |
| 507 | { |
| 508 | fNewRecipientAllowed = true; |
| 509 | return; |
| 510 | } |
| 511 | |
| 512 | bool send_failure = false; |
| 513 | if (retval == QMessageBox::Save) { |
| 514 | // "Create Unsigned" clicked |
| 515 | CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx())}; |
| 516 | PartiallySignedTransaction psbtx(mtx); |
| 517 | bool complete = false; |
| 518 | // Fill without signing |
| 519 | TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete); |
| 520 | assert(!complete); |
| 521 | assert(err == TransactionError::OK); |
| 522 | |
| 523 | // Copy PSBT to clipboard and offer to save |
| 524 | presentPSBT(psbtx); |
| 525 | } else { |
| 526 | // "Send" clicked |
| 527 | assert(!model->wallet().privateKeysDisabled() || model->wallet().hasExternalSigner()); |
| 528 | bool broadcast = true; |
| 529 | if (model->wallet().hasExternalSigner()) { |
| 530 | CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx())}; |
| 531 | PartiallySignedTransaction psbtx(mtx); |
| 532 | bool complete = false; |
| 533 | // Always fill without signing first. This prevents an external signer |
| 534 | // from being called prematurely and is not expensive. |
| 535 | TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete); |
| 536 | assert(!complete); |
| 537 | assert(err == TransactionError::OK); |
| 538 | send_failure = !signWithExternalSigner(psbtx, mtx, complete); |
| 539 | // Don't broadcast when user rejects it on the device or there's a failure: |
| 540 | broadcast = complete && !send_failure; |
| 541 | if (!send_failure) { |
| 542 | // A transaction signed with an external signer is not always complete, |
| 543 | // e.g. in a multisig wallet. |
| 544 | if (complete) { |
| 545 | // Prepare transaction for broadcast transaction if complete |
nothing calls this directly
no test coverage detected