| 808 | } |
| 809 | |
| 810 | util::Result<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const CoinsResult& pre_set_inputs, |
| 811 | const CAmount& nTargetValue, const CCoinControl& coin_control, |
| 812 | const CoinSelectionParams& coin_selection_params) |
| 813 | { |
| 814 | // Deduct preset inputs amount from the search target |
| 815 | CAmount selection_target = nTargetValue - pre_set_inputs.GetAppropriateTotal(coin_selection_params.m_subtract_fee_outputs).value_or(0); |
| 816 | |
| 817 | // Return if automatic coin selection is disabled, and we don't cover the selection target |
| 818 | if (!coin_control.m_allow_other_inputs && selection_target > 0) { |
| 819 | return util::Error{_("The preselected coins total amount does not cover the transaction target. " |
| 820 | "Please allow other inputs to be automatically selected or include more coins manually")}; |
| 821 | } |
| 822 | |
| 823 | OutputSet preset_coin_set; |
| 824 | for (const auto& output: pre_set_inputs.All()) { |
| 825 | preset_coin_set.insert(std::make_shared<COutput>(output)); |
| 826 | } |
| 827 | |
| 828 | // Return if we can cover the target only with the preset inputs |
| 829 | if (selection_target <= 0) { |
| 830 | SelectionResult result(nTargetValue, SelectionAlgorithm::MANUAL); |
| 831 | result.AddInputs(preset_coin_set, coin_selection_params.m_subtract_fee_outputs); |
| 832 | result.RecalculateWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee); |
| 833 | return result; |
| 834 | } |
| 835 | |
| 836 | // Return early if we cannot cover the target with the wallet's UTXO. |
| 837 | // We use the total effective value if we are not subtracting fee from outputs and 'available_coins' contains the data. |
| 838 | CAmount available_coins_total_amount = available_coins.GetAppropriateTotal(coin_selection_params.m_subtract_fee_outputs).value_or(0); |
| 839 | if (selection_target > available_coins_total_amount) { |
| 840 | return util::Error(); // Insufficient funds |
| 841 | } |
| 842 | |
| 843 | // Start wallet Coin Selection procedure |
| 844 | auto op_selection_result = AutomaticCoinSelection(wallet, available_coins, selection_target, coin_selection_params); |
| 845 | if (!op_selection_result) return op_selection_result; |
| 846 | |
| 847 | // If needed, add preset inputs to the automatic coin selection result |
| 848 | if (!pre_set_inputs.coins.empty()) { |
| 849 | auto preset_total = pre_set_inputs.GetAppropriateTotal(coin_selection_params.m_subtract_fee_outputs); |
| 850 | assert(preset_total.has_value()); |
| 851 | SelectionResult preselected(preset_total.value(), SelectionAlgorithm::MANUAL); |
| 852 | preselected.AddInputs(preset_coin_set, coin_selection_params.m_subtract_fee_outputs); |
| 853 | op_selection_result->Merge(preselected); |
| 854 | op_selection_result->RecalculateWaste(coin_selection_params.min_viable_change, |
| 855 | coin_selection_params.m_cost_of_change, |
| 856 | coin_selection_params.m_change_fee); |
| 857 | |
| 858 | // Verify we haven't exceeded the maximum allowed weight |
| 859 | int max_inputs_weight = coin_selection_params.m_max_tx_weight.value_or(MAX_STANDARD_TX_WEIGHT) - (coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR); |
| 860 | if (op_selection_result->GetWeight() > max_inputs_weight) { |
| 861 | return util::Error{_("The combination of the pre-selected inputs and the wallet automatic inputs selection exceeds the transaction maximum weight. " |
| 862 | "Please try sending a smaller amount or manually consolidating your wallet's UTXOs")}; |
| 863 | } |
| 864 | } |
| 865 | return op_selection_result; |
| 866 | } |
| 867 | |