| 472 | } |
| 473 | |
| 474 | CreatedTransactionResult FundTransaction(CWallet& wallet, const CMutableTransaction& tx, const std::vector<CRecipient>& recipients, const UniValue& options, CCoinControl& coinControl, bool override_min_fee) |
| 475 | { |
| 476 | // We want to make sure tx.vout is not used now that we are passing outputs as a vector of recipients. |
| 477 | // This sets us up to remove tx completely in a future PR in favor of passing the inputs directly. |
| 478 | CHECK_NONFATAL(tx.vout.empty()); |
| 479 | // Make sure the results are valid at least up to the most recent block |
| 480 | // the user could have gotten from another RPC command prior to now |
| 481 | wallet.BlockUntilSyncedToCurrentChain(); |
| 482 | |
| 483 | std::optional<unsigned int> change_position; |
| 484 | bool lockUnspents = false; |
| 485 | if (!options.isNull()) { |
| 486 | if (options.type() == UniValue::VBOOL) { |
| 487 | // backward compatibility bool only fallback, does nothing |
| 488 | } else { |
| 489 | RPCTypeCheckObj(options, |
| 490 | { |
| 491 | {"add_inputs", UniValueType(UniValue::VBOOL)}, |
| 492 | {"include_unsafe", UniValueType(UniValue::VBOOL)}, |
| 493 | {"add_to_wallet", UniValueType(UniValue::VBOOL)}, |
| 494 | {"changeAddress", UniValueType(UniValue::VSTR)}, |
| 495 | {"change_address", UniValueType(UniValue::VSTR)}, |
| 496 | {"changePosition", UniValueType(UniValue::VNUM)}, |
| 497 | {"change_position", UniValueType(UniValue::VNUM)}, |
| 498 | {"change_type", UniValueType(UniValue::VSTR)}, |
| 499 | {"includeWatching", UniValueType(UniValue::VBOOL)}, |
| 500 | {"include_watching", UniValueType(UniValue::VBOOL)}, |
| 501 | {"inputs", UniValueType(UniValue::VARR)}, |
| 502 | {"lockUnspents", UniValueType(UniValue::VBOOL)}, |
| 503 | {"lock_unspents", UniValueType(UniValue::VBOOL)}, |
| 504 | {"locktime", UniValueType(UniValue::VNUM)}, |
| 505 | {"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode() |
| 506 | {"feeRate", UniValueType()}, // will be checked by AmountFromValue() below |
| 507 | {"psbt", UniValueType(UniValue::VBOOL)}, |
| 508 | {"solving_data", UniValueType(UniValue::VOBJ)}, |
| 509 | {"subtractFeeFromOutputs", UniValueType(UniValue::VARR)}, |
| 510 | {"subtract_fee_from_outputs", UniValueType(UniValue::VARR)}, |
| 511 | {"replaceable", UniValueType(UniValue::VBOOL)}, |
| 512 | {"conf_target", UniValueType(UniValue::VNUM)}, |
| 513 | {"estimate_mode", UniValueType(UniValue::VSTR)}, |
| 514 | {"minconf", UniValueType(UniValue::VNUM)}, |
| 515 | {"maxconf", UniValueType(UniValue::VNUM)}, |
| 516 | {"input_weights", UniValueType(UniValue::VARR)}, |
| 517 | {"max_tx_weight", UniValueType(UniValue::VNUM)}, |
| 518 | }, |
| 519 | true, true); |
| 520 | |
| 521 | if (options.exists("add_inputs")) { |
| 522 | coinControl.m_allow_other_inputs = options["add_inputs"].get_bool(); |
| 523 | } |
| 524 | |
| 525 | if (options.exists("changeAddress") || options.exists("change_address")) { |
| 526 | const std::string change_address_str = (options.exists("change_address") ? options["change_address"] : options["changeAddress"]).get_str(); |
| 527 | CTxDestination dest = DecodeDestination(change_address_str); |
| 528 | |
| 529 | if (!IsValidDestination(dest)) { |
| 530 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Change address must be a valid bitcoin address"); |
| 531 | } |
no test coverage detected