Fix crypto payment refund system with proper account balance handling
- Fix AttributeError by changing payment.crypto_type to payment.coin_type
- Fix Decimal * float error by using Decimal("1e12") instead of 1e12
- Add account-specific balance checking using payment.account_index
- Add comprehensive logging for refund attempts and wallet balance checks
- Update execute_refund to accept payment object for account context
- Ensure refunds are sent from correct account that received the funds
This resolves GroupR's underpayment refund issue and improves the reliability
of the crypto payment rescue system.
This commit is contained in:
parent
88566599ce
commit
581f2b2244
2 changed files with 66 additions and 12 deletions
|
|
@ -149,28 +149,75 @@ class PaymentRescue:
|
|||
"reason": "Payment received after quote expiration",
|
||||
}
|
||||
|
||||
def execute_refund(self, refund_details):
|
||||
def execute_refund(self, refund_details, payment=None):
|
||||
"""
|
||||
Execute the actual refund transaction.
|
||||
|
||||
Args:
|
||||
refund_details: dict with refund information
|
||||
payment: CryptoPayment object (needed for account_index)
|
||||
|
||||
Returns:
|
||||
dict with transaction details or raises exception
|
||||
"""
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
refund_amount_xmr = refund_details["refund_amount"]
|
||||
refund_amount_piconero = int(refund_amount_xmr * Decimal("1e12"))
|
||||
|
||||
logger.info(f"Attempting to refund payment {refund_details['payment_id']}")
|
||||
logger.info(
|
||||
f"Refund amount: {refund_amount_xmr} XMR ({refund_amount_piconero} piconero)"
|
||||
)
|
||||
logger.info(f"Refund address: {refund_details['refund_address']}")
|
||||
logger.info(f"Refund reason: {refund_details['reason']}")
|
||||
|
||||
# Check wallet balance for the specific account before attempting refund
|
||||
account_index = payment.account_index if payment else 0
|
||||
logger.info(f"Checking balance for account {account_index}")
|
||||
|
||||
try:
|
||||
# Create the refund transaction
|
||||
tx_result = self.crypto_client.transfer(
|
||||
destinations=[
|
||||
balance_result = self.crypto_client._call(
|
||||
"get_balance", {"account_index": account_index}
|
||||
)
|
||||
unlocked_balance = balance_result.get("unlocked_balance", 0)
|
||||
total_balance = balance_result.get("balance", 0)
|
||||
logger.info(
|
||||
f"Account {account_index} balance - Total: {total_balance} piconero ({Decimal(total_balance) / Decimal('1e12')} XMR)"
|
||||
)
|
||||
logger.info(
|
||||
f"Account {account_index} balance - Unlocked: {unlocked_balance} piconero ({Decimal(unlocked_balance) / Decimal('1e12')} XMR)"
|
||||
)
|
||||
|
||||
if unlocked_balance < refund_amount_piconero:
|
||||
logger.warning(
|
||||
f"Insufficient unlocked balance in account {account_index}: need {refund_amount_piconero} but only have {unlocked_balance} unlocked"
|
||||
)
|
||||
except Exception as balance_error:
|
||||
logger.warning(
|
||||
f"Could not check wallet balance for account {account_index}: {balance_error}"
|
||||
)
|
||||
|
||||
try:
|
||||
# Create the refund transaction from the specific account that received the payment
|
||||
transfer_params = {
|
||||
"destinations": [
|
||||
{
|
||||
"address": refund_details["refund_address"],
|
||||
"amount": int(
|
||||
refund_details["refund_amount"] * 1e12
|
||||
), # Convert to piconero
|
||||
"amount": refund_amount_piconero,
|
||||
}
|
||||
]
|
||||
)
|
||||
],
|
||||
"account_index": account_index, # Specify the account that received the funds
|
||||
"get_tx_key": True,
|
||||
"do_not_relay": False,
|
||||
"priority": 1, # Use low priority to reduce fees
|
||||
}
|
||||
|
||||
logger.info(f"Calling transfer with params: {transfer_params}")
|
||||
tx_result = self.crypto_client._call("transfer", transfer_params)
|
||||
logger.info(f"Transfer successful: {tx_result}")
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
|
|
@ -180,4 +227,7 @@ class PaymentRescue:
|
|||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Refund failed for payment {refund_details['payment_id']}: {e}"
|
||||
)
|
||||
return {"success": False, "error": str(e), "refund_details": refund_details}
|
||||
|
|
|
|||
|
|
@ -884,7 +884,9 @@ def process_payment(
|
|||
logger.info(
|
||||
f"Expired payment {crypto_payment.id} eligible for refund: {refund_details}"
|
||||
)
|
||||
result = payment_rescue.execute_refund(refund_details)
|
||||
result = payment_rescue.execute_refund(
|
||||
refund_details, crypto_payment
|
||||
)
|
||||
if result["success"]:
|
||||
logger.info(
|
||||
f"Refund executed for expired payment {crypto_payment.id}: TX {result['tx_hash']}"
|
||||
|
|
@ -1083,7 +1085,7 @@ def process_payment(
|
|||
logger.info(
|
||||
f"Overpayment detected for {crypto_payment.id}: {refund_details}"
|
||||
)
|
||||
result = payment_rescue.execute_refund(refund_details)
|
||||
result = payment_rescue.execute_refund(refund_details, crypto_payment)
|
||||
if result["success"]:
|
||||
logger.info(
|
||||
f"Excess refunded for payment {crypto_payment.id}: TX {result['tx_hash']}"
|
||||
|
|
@ -1145,7 +1147,9 @@ def process_payment(
|
|||
logger.info(
|
||||
f"Underpayment {crypto_payment.id} eligible for refund: {refund_details}"
|
||||
)
|
||||
result = payment_rescue.execute_refund(refund_details)
|
||||
result = payment_rescue.execute_refund(
|
||||
refund_details, crypto_payment
|
||||
)
|
||||
if result["success"]:
|
||||
logger.info(
|
||||
f"Refund executed for underpayment {crypto_payment.id}: TX {result['tx_hash']}"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue