@@ -968,6 +968,12 @@ async def do_command():
968
968
default = 1000000000000 ,
969
969
show_default = True ,
970
970
)
971
+ @click .option (
972
+ "-ps" ,
973
+ "--previous-spends" ,
974
+ help = "A comma separated list of previously generated spend bundle files to simulate spending first (in order)" ,
975
+ default = None ,
976
+ )
971
977
def payments_cmd (
972
978
db_path : str ,
973
979
pubkeys : str ,
@@ -977,6 +983,7 @@ def payments_cmd(
977
983
maximum_extra_cost : Optional [int ],
978
984
amount_threshold : int ,
979
985
filename : Optional [str ],
986
+ previous_spends : Optional [str ],
980
987
):
981
988
# Check to make sure we've been given a correct set of parameters
982
989
if amount % 2 == 1 :
@@ -994,6 +1001,61 @@ async def do_command():
994
1001
clawforward_ph : bytes32 = decode_puzzle_hash (recipient_address )
995
1002
fee_conditions : List [Program ] = [Program .to ([60 , b"" ])]
996
1003
1004
+ # Handle previous spends if provided
1005
+ current_coin = current_singleton .coin
1006
+ current_lineage_proof = current_singleton .lineage_proof
1007
+
1008
+ if previous_spends :
1009
+ previous_spend_files = previous_spends .split ("," )
1010
+ for spend_file in previous_spend_files :
1011
+ try :
1012
+ # Read the unsigned spend
1013
+ unsigned_spend = read_unsigned_spend (spend_file .strip ())
1014
+
1015
+ # Extract the coin spend for the singleton (first one should be the singleton)
1016
+ if len (unsigned_spend .coin_spends ) == 0 :
1017
+ raise ValueError (f"No coin spends found in { spend_file } " )
1018
+
1019
+ # Get the singleton coin spend
1020
+ singleton_spend = unsigned_spend .coin_spends [0 ]
1021
+
1022
+ # Extract the payment amount from the spend bundle
1023
+ # We need to parse the solution to get the out_amount
1024
+ try :
1025
+ # The HSM coin spend has the solution as a Program, not bytes
1026
+ # We can work with it directly
1027
+ solution = singleton_spend .solution
1028
+ out_amount , in_amount , p2_ph = get_spend_params_for_ach_creation (solution )
1029
+
1030
+ # Calculate the new amount after this payment
1031
+ # out_amount is what we're paying out
1032
+ # in_amount is what we're absorbing from p2_singletons
1033
+ net_change = in_amount - out_amount
1034
+ new_amount = current_coin .amount + net_change
1035
+
1036
+ except Exception as parse_error :
1037
+ raise ValueError (f"Cannot parse previous spend bundle { spend_file } . The tool needs to be able to extract the payment amount from the spend bundle to calculate the correct coin state." )
1038
+
1039
+ # Safety check: ensure new_amount is not negative
1040
+ if new_amount < 0 :
1041
+ raise ValueError (f"Calculated new amount { new_amount } is negative. This indicates an error in the calculation." )
1042
+
1043
+ # Update for next iteration
1044
+ previous_coin : Coin = current_coin
1045
+ current_coin = Coin (
1046
+ previous_coin .name (),
1047
+ current_coin .puzzle_hash ,
1048
+ new_amount
1049
+ )
1050
+ current_lineage_proof = LineageProof (
1051
+ previous_coin .parent_coin_info ,
1052
+ construct_singleton_inner_puzzle (derivation .prefarm_info ).get_tree_hash (),
1053
+ previous_coin .amount ,
1054
+ )
1055
+
1056
+ except Exception as e :
1057
+ raise ValueError (f"Error processing previous spend file { spend_file } : { e } " )
1058
+
997
1059
# Get any p2_singletons to spend
998
1060
if absorb_available_payments :
999
1061
max_num : Optional [uint32 ] = (
@@ -1010,10 +1072,10 @@ async def do_command():
1010
1072
1011
1073
# Get the spend bundle
1012
1074
singleton_bundle , data_to_sign = get_withdrawal_spend_info (
1013
- current_singleton . coin ,
1075
+ current_coin ,
1014
1076
pubkey_list ,
1015
1077
derivation ,
1016
- current_singleton . lineage_proof ,
1078
+ current_lineage_proof ,
1017
1079
amount ,
1018
1080
clawforward_ph ,
1019
1081
p2_singletons_to_claim = p2_singletons ,
0 commit comments