feat: migrate payment service escrow operations to use centralized aitbc package HTTP client
Some checks failed
API Endpoint Tests / test-api-endpoints (push) Successful in 11s
Integration Tests / test-service-integration (push) Successful in 44s
Python Tests / test-python (push) Failing after 1m24s
Security Scanning / security-scan (push) Has started running

- Replace httpx.AsyncClient with aitbc.AITBCHTTPClient in _create_bitcoin_escrow, release_payment, refund_payment
- Remove async context manager in favor of direct AITBCHTTPClient usage
- Replace status code checks with NetworkError exception handling
- Remove httpx import (no longer needed)
- Remove blank line after aitbc imports
- Consistent error handling across all escrow operations
This commit is contained in:
aitbc
2026-04-24 23:48:45 +02:00
parent 9f51498725
commit 92ca4daaa7

View File

@@ -10,7 +10,6 @@ from datetime import datetime, timedelta
from __future__ import annotations from __future__ import annotations
from aitbc import get_logger, AITBCHTTPClient, NetworkError from aitbc import get_logger, AITBCHTTPClient, NetworkError
logger = get_logger(__name__) logger = get_logger(__name__)
from ..domain.payment import JobPayment, PaymentEscrow from ..domain.payment import JobPayment, PaymentEscrow
@@ -114,35 +113,36 @@ class PaymentService:
async def _create_bitcoin_escrow(self, payment: JobPayment) -> None: async def _create_bitcoin_escrow(self, payment: JobPayment) -> None:
"""Create an escrow for Bitcoin payments (exchange only)""" """Create an escrow for Bitcoin payments (exchange only)"""
try: try:
async with httpx.AsyncClient() as client: client = AITBCHTTPClient(timeout=30.0)
try:
# Call wallet daemon to create escrow # Call wallet daemon to create escrow
response = await client.post( escrow_data = client.post(
f"{self.wallet_base_url}/api/v1/escrow/create", f"{self.wallet_base_url}/api/v1/escrow/create",
json={"amount": float(payment.amount), "currency": payment.currency, "timeout_seconds": 3600}, # 1 hour json={"amount": float(payment.amount), "currency": payment.currency, "timeout_seconds": 3600}, # 1 hour
) )
payment.escrow_address = escrow_data["address"]
payment.status = "escrowed"
payment.escrowed_at = datetime.utcnow()
payment.updated_at = datetime.utcnow()
if response.status_code == 200: # Create escrow record
escrow_data = response.json() escrow = PaymentEscrow(
payment.escrow_address = escrow_data["address"] payment_id=payment.id,
payment.status = "escrowed" amount=payment.amount,
payment.escrowed_at = datetime.utcnow() currency=payment.currency,
payment.updated_at = datetime.utcnow() address=escrow_data["address"],
expires_at=datetime.utcnow() + timedelta(hours=1),
)
if escrow is not None:
self.session.add(escrow)
# Create escrow record self.session.commit()
escrow = PaymentEscrow( logger.info(f"Created Bitcoin escrow for payment {payment.id}")
payment_id=payment.id, except NetworkError as e:
amount=payment.amount, logger.error(f"Failed to create Bitcoin escrow: {e}")
currency=payment.currency, payment.status = "failed"
address=escrow_data["address"], payment.updated_at = datetime.utcnow()
expires_at=datetime.utcnow() + timedelta(hours=1), self.session.commit()
)
if escrow is not None:
self.session.add(escrow)
self.session.commit()
logger.info(f"Created Bitcoin escrow for payment {payment.id}")
else:
logger.error(f"Failed to create Bitcoin escrow: {response.text}")
except Exception as e: except Exception as e:
logger.error(f"Error creating Bitcoin escrow: {e}") logger.error(f"Error creating Bitcoin escrow: {e}")
@@ -161,37 +161,35 @@ class PaymentService:
return False return False
try: try:
async with httpx.AsyncClient() as client: client = AITBCHTTPClient(timeout=30.0)
try:
# Call wallet daemon to release escrow # Call wallet daemon to release escrow
response = await client.post( release_data = client.post(
f"{self.wallet_base_url}/api/v1/escrow/release", f"{self.wallet_base_url}/api/v1/escrow/release",
json={"address": payment.escrow_address, "reason": reason or "Job completed successfully"}, json={"address": payment.escrow_address, "reason": reason or "Job completed successfully"},
) )
payment.status = "released"
payment.released_at = datetime.utcnow()
payment.updated_at = datetime.utcnow()
payment.transaction_hash = release_data.get("transaction_hash")
if response.status_code == 200: # Update escrow record
release_data = response.json() escrow = (
payment.status = "released" self.session.execute(select(PaymentEscrow).where(PaymentEscrow.payment_id == payment_id))
payment.released_at = datetime.utcnow() .scalars()
payment.updated_at = datetime.utcnow() .first()
payment.transaction_hash = release_data.get("transaction_hash") )
# Update escrow record if escrow:
escrow = ( escrow.is_released = True
self.session.execute(select(PaymentEscrow).where(PaymentEscrow.payment_id == payment_id)) escrow.released_at = datetime.utcnow()
.scalars()
.first()
)
if escrow: self.session.commit()
escrow.is_released = True logger.info(f"Released payment {payment_id} for job {job_id}")
escrow.released_at = datetime.utcnow() return True
except NetworkError as e:
self.session.commit() logger.error(f"Failed to release payment: {e}")
logger.info(f"Released payment {payment_id} for job {job_id}") return False
return True
else:
logger.error(f"Failed to release payment: {response.text}")
return False
except Exception as e: except Exception as e:
logger.error(f"Error releasing payment: {e}") logger.error(f"Error releasing payment: {e}")
@@ -208,9 +206,10 @@ class PaymentService:
return False return False
try: try:
async with httpx.AsyncClient() as client: client = AITBCHTTPClient(timeout=30.0)
try:
# Call wallet daemon to refund # Call wallet daemon to refund
response = await client.post( refund_data = client.post(
f"{self.wallet_base_url}/api/v1/refund", f"{self.wallet_base_url}/api/v1/refund",
json={ json={
"payment_id": payment_id, "payment_id": payment_id,
@@ -219,31 +218,28 @@ class PaymentService:
"reason": reason, "reason": reason,
}, },
) )
payment.status = "refunded"
payment.refunded_at = datetime.utcnow()
payment.updated_at = datetime.utcnow()
payment.refund_transaction_hash = refund_data.get("transaction_hash")
if response.status_code == 200: # Update escrow record
refund_data = response.json() escrow = (
payment.status = "refunded" self.session.execute(select(PaymentEscrow).where(PaymentEscrow.payment_id == payment_id))
payment.refunded_at = datetime.utcnow() .scalars()
payment.updated_at = datetime.utcnow() .first()
payment.refund_transaction_hash = refund_data.get("transaction_hash") )
# Update escrow record if escrow:
escrow = ( escrow.is_refunded = True
self.session.execute(select(PaymentEscrow).where(PaymentEscrow.payment_id == payment_id)) escrow.refunded_at = datetime.utcnow()
.scalars()
.first()
)
if escrow: self.session.commit()
escrow.is_refunded = True logger.info(f"Refunded payment {payment_id} for job {job_id}")
escrow.refunded_at = datetime.utcnow() return True
except NetworkError as e:
self.session.commit() logger.error(f"Failed to refund payment: {e}")
logger.info(f"Refunded payment {payment_id} for job {job_id}") return False
return True
else:
logger.error(f"Failed to refund payment: {response.text}")
return False
except Exception as e: except Exception as e:
logger.error(f"Error refunding payment: {e}") logger.error(f"Error refunding payment: {e}")