From 29b04384161ffa2d97552b7b66ffa5d36e08ca64 Mon Sep 17 00:00:00 2001 From: counterweight Date: Tue, 23 Dec 2025 10:39:09 +0100 Subject: [PATCH] fix: Prevent user from cancelling trades after slot time has passed Users can no longer cancel trades once the slot time has passed. Added test to verify this behavior. --- backend/routes/exchange.py | 8 +++++++- backend/tests/test_exchange.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/backend/routes/exchange.py b/backend/routes/exchange.py index 26b2603..3e95f98 100644 --- a/backend/routes/exchange.py +++ b/backend/routes/exchange.py @@ -548,7 +548,13 @@ async def cancel_my_trade( detail=f"Cannot cancel: status is '{exchange.status.value}'", ) - # Cancel the exchange (no time restriction per spec) + # Check if slot time has already passed + if exchange.slot_start <= datetime.now(UTC): + raise HTTPException( + status_code=400, + detail="Cannot cancel: trade slot time has already passed", + ) + exchange.status = ExchangeStatus.CANCELLED_BY_USER exchange.cancelled_at = datetime.now(UTC) diff --git a/backend/tests/test_exchange.py b/backend/tests/test_exchange.py index e637f79..91ba0ad 100644 --- a/backend/tests/test_exchange.py +++ b/backend/tests/test_exchange.py @@ -543,6 +543,39 @@ class TestCancelTrade: assert response.status_code == 400 assert "cancelled_by_user" in response.json()["detail"] + @pytest.mark.asyncio + async def test_cannot_cancel_past_trade( + self, client_factory, regular_user, admin_user + ): + """Cannot cancel a trade after the slot time has passed.""" + # Create a past trade directly in DB + async with client_factory.get_db_session() as db: + await create_price_in_db(db, price=20000.0) + past_time = datetime.now(UTC) - timedelta(hours=1) + exchange = Exchange( + user_id=regular_user["user"]["id"], + slot_start=past_time, + slot_end=past_time + timedelta(minutes=15), + direction=TradeDirection.BUY, + eur_amount=10000, + sats_amount=500000, + market_price_eur=20000.0, + agreed_price_eur=21000.0, + premium_percentage=5, + status=ExchangeStatus.BOOKED, + ) + db.add(exchange) + await db.commit() + await db.refresh(exchange) + trade_id = exchange.id + + # User tries to cancel + async with client_factory.create(cookies=regular_user["cookies"]) as client: + response = await client.post(f"/api/trades/{trade_id}/cancel") + + assert response.status_code == 400 + assert "already passed" in response.json()["detail"] + # ============================================================================= # Admin Trades Tests