33"""
44
55import random
6+ from copy import deepcopy
67from typing import Iterable , List , Optional , Tuple
78
89from pycardano .address import Address
@@ -36,6 +37,7 @@ def select(
3637 max_input_count : Optional [int ] = None ,
3738 include_max_fee : Optional [bool ] = True ,
3839 respect_min_utxo : Optional [bool ] = True ,
40+ existing_amount : Optional [Value ] = None ,
3941 ) -> Tuple [List [UTxO ], Value ]:
4042 """From an input list of UTxOs, select a subset of UTxOs whose sum (including ADA and multi-assets)
4143 is equal to or larger than the sum of a set of outputs.
@@ -50,6 +52,7 @@ def select(
5052 respect_min_utxo (bool): Respect minimum amount of ADA required to hold a multi-asset bundle in the change.
5153 Defaults to True. If disabled, the selection will not add addition amount of ADA to change even
5254 when the amount is too small to hold a multi-asset bundle.
55+ existing_amount (Value): A starting amount already existed before selection. Defaults to 0.
5356
5457 Returns:
5558 Tuple[List[UTxO], Value]: A tuple containing:
@@ -83,6 +86,7 @@ def select(
8386 max_input_count : Optional [int ] = None ,
8487 include_max_fee : Optional [bool ] = True ,
8588 respect_min_utxo : Optional [bool ] = True ,
89+ existing_amount : Optional [Value ] = None ,
8690 ) -> Tuple [List [UTxO ], Value ]:
8791 available : List [UTxO ] = sorted (utxos , key = lambda utxo : utxo .output .lovelace )
8892 max_fee = max_tx_fee (context ) if include_max_fee else 0
@@ -91,15 +95,14 @@ def select(
9195 total_requested += o .amount
9296
9397 selected = []
94- selected_amount = Value ()
98+ selected_amount = existing_amount if existing_amount is not None else Value ()
9599
96100 while not total_requested <= selected_amount :
97101 if not available :
98102 raise InsufficientUTxOBalanceException ("UTxO Balance insufficient!" )
99103 to_add = available .pop ()
100104 selected .append (to_add )
101105 selected_amount += to_add .output .amount
102-
103106 if max_input_count and len (selected ) > max_input_count :
104107 raise MaxInputCountExceededException (
105108 f"Max input count: { max_input_count } exceeded!"
@@ -108,9 +111,8 @@ def select(
108111 if respect_min_utxo :
109112 change = selected_amount - total_requested
110113 min_change_amount = min_lovelace_post_alonzo (
111- TransactionOutput (_FAKE_ADDR , change ), context
114+ TransactionOutput (_FAKE_ADDR , deepcopy ( change ) ), context
112115 )
113-
114116 if change .coin < min_change_amount :
115117 additional , _ = self .select (
116118 available ,
@@ -127,7 +129,6 @@ def select(
127129 for u in additional :
128130 selected .append (u )
129131 selected_amount += u .output .amount
130-
131132 return selected , selected_amount - total_requested
132133
133134
@@ -218,10 +219,9 @@ def _find_diff_by_former(a: Value, b: Value) -> int:
218219 else :
219220 policy_id = list (a .multi_asset .keys ())[0 ]
220221 asset_name = list (a .multi_asset [policy_id ].keys ())[0 ]
221- return (
222- a .multi_asset [policy_id ][asset_name ]
223- - b .multi_asset [policy_id ][asset_name ]
224- )
222+ return a .multi_asset [policy_id ].get (asset_name , 0 ) - b .multi_asset [
223+ policy_id
224+ ].get (asset_name , 0 )
225225
226226 def _improve (
227227 self ,
@@ -272,6 +272,7 @@ def select(
272272 max_input_count : Optional [int ] = None ,
273273 include_max_fee : Optional [bool ] = True ,
274274 respect_min_utxo : Optional [bool ] = True ,
275+ existing_amount : Optional [Value ] = None ,
275276 ) -> Tuple [List [UTxO ], Value ]:
276277 # Shallow copy the list
277278 remaining = list (utxos )
@@ -281,11 +282,13 @@ def select(
281282 request_sum += o .amount
282283
283284 assets = self ._split_by_asset (request_sum )
285+
284286 request_sorted = sorted (assets , key = self ._get_single_asset_val , reverse = True )
285287
286288 # Phase 1 - random select
287289 selected : List [UTxO ] = []
288- selected_amount = Value ()
290+ selected_amount = existing_amount if existing_amount is not None else Value ()
291+
289292 for r in request_sorted :
290293 self ._random_select_subset (r , remaining , selected , selected_amount )
291294 if max_input_count and len (selected ) > max_input_count :
@@ -315,7 +318,7 @@ def select(
315318 if respect_min_utxo :
316319 change = selected_amount - request_sum
317320 min_change_amount = min_lovelace_post_alonzo (
318- TransactionOutput (_FAKE_ADDR , change ), context
321+ TransactionOutput (_FAKE_ADDR , deepcopy ( change ) ), context
319322 )
320323
321324 if change .coin < min_change_amount :
0 commit comments