@@ -614,15 +614,28 @@ namespace sdk {
614614 // Add all outputs and compute the total amount of satoshi to be sent
615615 amount required_total{ 0 };
616616
617+ uint32_t explicit_change_index = NO_CHANGE_INDEX;
617618 if (num_addressees) {
619+ size_t addressee_index = 0 ;
618620 for (auto & addressee : *addressees_p) {
619621 const auto addressee_asset_id = asset_id_from_json (net_params, addressee);
620622 if (addressee_asset_id == asset_id) {
621- required_total += add_tx_addressee (session, net_params, result, tx, addressee);
623+ const auto amount = add_tx_addressee (session, net_params, result, tx, addressee);
624+ if (!json_get_value (addressee, " is_change" , false )) {
625+ required_total += amount;
626+ } else {
627+ if (explicit_change_index != NO_CHANGE_INDEX) {
628+ set_tx_error (result, " Only one explicit change addressee allowed" );
629+ break ;
630+ }
631+ explicit_change_index = addressee_index;
632+ }
622633 reordered_addressees.push_back (addressee);
623634 }
635+ ++addressee_index;
624636 }
625637 }
638+ result[" change_type" ][asset_id] = explicit_change_index == NO_CHANGE_INDEX ? " generated" : " explicit" ;
626639
627640 // TODO: filter per asset or assume always single asset
628641 if (manual_selection) {
@@ -758,11 +771,7 @@ namespace sdk {
758771 // so compute what we can send (everything minus the
759772 // fee) and exit the loop
760773 required_total = available_total - fee;
761- if (is_liquid) {
762- set_tx_output_commitment (net_params, tx, 0 , asset_id, required_total.value ());
763- } else {
764- tx->outputs [0 ].satoshi = required_total.value ();
765- }
774+ set_tx_output_value (net_params, tx, 0 , asset_id, required_total.value ());
766775 if (num_addressees == 1u ) {
767776 addressees_p->at (0 )[" satoshi" ] = required_total.value ();
768777 }
@@ -818,17 +827,30 @@ namespace sdk {
818827 continue ;
819828 }
820829
821- // We have more than the dust amount of change. Add a change
822- // output to collect it, then loop again in case the amount
823- // this increases the fee by requires more UTXOs.
824- add_tx_output (net_params, result, tx, result.at (" change_address" ).at (asset_id).at (" address" ),
825- is_liquid ? 1 : 0 , asset_id == " btc" ? std::string{} : asset_id);
826- have_change_output = true ;
827- change_index = tx->num_outputs - 1 ;
828- if (is_liquid && include_fee) {
829- std::swap (tx->outputs [fee_index], tx->outputs [change_index]);
830- std::swap (fee_index, change_index);
830+ // We have more than the dust amount of change. First look for an explicit change
831+ // output in the addressees and if present send the change there
832+ amount::value_type change_amount = (total - required_total - fee).value ();
833+
834+ if (explicit_change_index == NO_CHANGE_INDEX) {
835+ // No explicit change output specified, add a change output using the generated change
836+ // address
837+ add_tx_output (net_params, result, tx, result.at (" change_address" ).at (asset_id).at (" address" ),
838+ is_liquid ? 1 : 0 , asset_id == " btc" ? std::string{} : asset_id);
839+ have_change_output = true ;
840+ change_index = tx->num_outputs - 1 ;
841+ if (is_liquid && include_fee) {
842+ std::swap (tx->outputs [fee_index], tx->outputs [change_index]);
843+ std::swap (fee_index, change_index);
844+ }
845+ } else {
846+ // Use explicit change output
847+ set_tx_output_value (net_params, tx, explicit_change_index, asset_id, change_amount);
848+ auto addressees = *addressees_p;
849+ addressees[explicit_change_index][" satoshi" ] = change_amount;
850+ change_index = explicit_change_index;
851+ have_change_output = true ;
831852 }
853+
832854 result[" have_change" ][asset_id] = have_change_output;
833855 result[" change_index" ][asset_id] = change_index;
834856 }
@@ -850,11 +872,13 @@ namespace sdk {
850872 } else {
851873 auto & change_output = tx->outputs [change_index];
852874 change_output.satoshi = change_amount;
853- const uint32_t new_change_index = get_uniform_uint32_t (tx->num_outputs );
854- // Randomize change output
855- if (change_index != new_change_index) {
856- std::swap (tx->outputs [new_change_index], change_output);
857- change_index = new_change_index;
875+ if (explicit_change_index == NO_CHANGE_INDEX) {
876+ // Randomize change output for non-explicit change
877+ const uint32_t new_change_index = get_uniform_uint32_t (tx->num_outputs );
878+ if (change_index != new_change_index) {
879+ std::swap (tx->outputs [new_change_index], change_output);
880+ change_index = new_change_index;
881+ }
858882 }
859883 }
860884 }
0 commit comments