diff --git a/make_post_sell/lib/crypto_watcher.py b/make_post_sell/lib/crypto_watcher.py index 3553e44..5b35b9f 100644 --- a/make_post_sell/lib/crypto_watcher.py +++ b/make_post_sell/lib/crypto_watcher.py @@ -600,7 +600,7 @@ def process_payment( except Exception as e: logger.error(f"Failed to process full refund for expired payment {crypto_payment.id}: {e}") - elif payment_rescue: + elif payment_rescue and crypto_payment.refund_address: # Not out of stock - do normal expired refund with restocking fee coin_config = get_coin_config(crypto_payment.coin_type) received_crypto = Decimal(total_recv) / coin_config["atomic_units"] @@ -620,42 +620,57 @@ def process_payment( crypto_payment.refund_amount = int(refund_details["refund_amount"] * coin_config["atomic_units"]) crypto_payment.refund_tx_hash = result["tx_hash"] crypto_payment.refund_reason = refund_details["reason"] + crypto_payment.status = CryptoPayment.STATUS_EXPIRED_REFUNDED - # Now sweep the restocking fee to shop's wallet + # Commit the refund first + env_request.dbsession.add(crypto_payment) + env_request.dbsession.flush() + + # Now sweep the remaining restocking fee to shop's wallet (AFTER refund) fee_amount = int(refund_details["fee_amount"] * coin_config["atomic_units"]) if fee_amount > 0 and crypto_payment.shop_sweep_to_address: try: + # Small delay to ensure refund tx is processed + import time + time.sleep(2) + if crypto_payment.coin_type == "XMR": - sweep_result = client._call("sweep_single", { + # Send exact restocking fee amount (9%) + sweep_result = client._call("transfer", { "account_index": crypto_payment.account_index, - "address": crypto_payment.shop_sweep_to_address, - "amount": fee_amount, + "destinations": [{ + "address": crypto_payment.shop_sweep_to_address, + "amount": fee_amount + }], "priority": 1, "get_tx_hex": True, "do_not_relay": False, }) - fee_tx_hash = sweep_result.get("tx_hash_list", [None])[0] + fee_tx_hash = sweep_result.get("tx_hash") + actual_swept = fee_amount elif crypto_payment.coin_type == "DOGE": + # Send exact restocking fee amount + fee_crypto_amount = float(Decimal(fee_amount) / coin_config["atomic_units"]) fee_tx_hash = client._call("sendtoaddress", [ crypto_payment.shop_sweep_to_address, - float(Decimal(fee_amount) / coin_config["atomic_units"]) + fee_crypto_amount ]) + actual_swept = fee_amount else: fee_tx_hash = None + actual_swept = 0 - if fee_tx_hash: - crypto_payment.swept_amount = fee_amount + if fee_tx_hash and actual_swept > 0: + crypto_payment.swept_amount = actual_swept crypto_payment.swept_tx_hash = fee_tx_hash crypto_payment.swept_timestamp = now_timestamp() logger.info( f"Restocking fee swept for payment {crypto_payment.id}: " - f"{Decimal(fee_amount) / coin_config['atomic_units']} {crypto_payment.coin_type} " + f"{Decimal(actual_swept) / coin_config['atomic_units']} {crypto_payment.coin_type} " f"TX: {fee_tx_hash}" ) except Exception as e: logger.error(f"Failed to sweep restocking fee for payment {crypto_payment.id}: {e}") - - crypto_payment.status = CryptoPayment.STATUS_EXPIRED_REFUNDED else: logger.error( f"Refund failed for expired payment {crypto_payment.id}: {result['error']}" @@ -738,6 +753,7 @@ def process_payment( # Check for overpayment refund AFTER confirming the order (applies to both new and stuck payments) if ( payment_rescue + and crypto_payment.refund_address and crypto_payment.received_amount > crypto_payment.expected_amount and crypto_payment.invoice and crypto_payment.invoice.user @@ -781,6 +797,7 @@ def process_payment( # Check for underpayment rescue when we have enough confirmations if ( payment_rescue + and crypto_payment.refund_address and min_confs >= int(crypto_payment.confirmations_required) and crypto_payment.invoice and crypto_payment.invoice.user