SPB Git forge
1commits 1branches 0releases
189.0 KBsize
maindefault branch
5 h agolast push
Python 54.7% TypeScript 42.5% SQL 1.9%
2.9 KB · 62 lines python
Raw Blame History
1"""Credential preflight: discover what the configured keys can do without ever placing a live order."""23from __future__ import annotations45import time6from decimal import Decimal7from typing import Any89from ktrade.api.deps import AppState10from ktrade.kraken.rest import KrakenAPIError, KrakenREST111213async def _probe(rest: KrakenREST, name: str, coro) -> dict[str, Any]:  # noqa: ANN00114    try:15        await coro16        return {"ok": True}17    except KrakenAPIError as e:18        return {"ok": False, "permission_denied": e.is_permission, "error": str(e)}19    except Exception as e:  # noqa: BLE00120        return {"ok": False, "error": str(e)}212223async def run_preflight(st: AppState) -> dict[str, Any]:24    out: dict[str, Any] = {"checked_at": time.time(), "data_key": None, "trade_key": None}25    s = st.settings26    if s.has_data_key():27        rest = st.rest28        d: dict[str, Any] = {}29        d["balance"] = await _probe(rest, "balance", rest.balance())30        d["open_orders"] = await _probe(rest, "open_orders", rest.open_orders())31        d["trade_volume"] = await _probe(rest, "trade_volume", rest.trade_volume(["XXBTZUSD"]))32        d["ws_token"] = await _probe(rest, "ws_token", rest.websockets_token())33        # Trade-permission probe: validate-only order that could never execute (price = 10% of market, min size,34        # expires in 5 s). The data key SHOULD fail this with Permission denied (least privilege).35        d["trade_permission"] = await _trade_probe(rest)36        if d["trade_permission"].get("has_trade_permission"):37            d["warning"] = "The data/account key has order permission — least-privilege violated; create a read-only key for data."38        out["data_key"] = d39    if s.has_trade_key():40        trade_rest = KrakenREST(s.kraken_rest_url, s.kraken_trade_api_key, s.kraken_trade_api_secret, s.kraken_tier)41        try:42            out["trade_key"] = {"trade_permission": await _trade_probe(trade_rest), "note": "live mode is disabled (feature flag + UI activation required)"}43        finally:44            await trade_rest.aclose()45    return out464748async def _trade_probe(rest: KrakenREST) -> dict[str, Any]:49    try:50        tick = await rest.ticker(["XXBTZUSD"])51        last = Decimal(next(iter(tick.values()))["c"][0])52        price = (last * Decimal("0.10")).quantize(Decimal("0.1"))53        r = await rest.add_order(pair="XXBTZUSD", side="buy", ordertype="limit", volume="0.0001", price=str(price), timeinforce="GTC", validate=True)54        return {"has_trade_permission": True, "validated": r.get("descr")}55    except KrakenAPIError as e:56        if e.is_permission:57            return {"has_trade_permission": False, "error": str(e)}58        # any other validation error means the permission check passed59        return {"has_trade_permission": True, "error": str(e)}60    except Exception as e:  # noqa: BLE00161        return {"has_trade_permission": None, "error": str(e)}62