mirror of
https://github.com/Routstr/routstr-core.git
synced 2026-07-22 12:22:20 +00:00
Compare commits
11 Commits
90da3803c6
...
fix-x-cash
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4b825cad8 | ||
|
|
6cff06f9aa | ||
|
|
6c8a4a14ae | ||
|
|
5c7820ef41 | ||
|
|
047215df80 | ||
|
|
d69720f39f | ||
|
|
77a90ac7d6 | ||
|
|
9741218edd | ||
|
|
1f3d2dcd62 | ||
|
|
55bb8ecf11 | ||
|
|
8432561652 |
39
Dockerfile
39
Dockerfile
@@ -1,28 +1,39 @@
|
||||
FROM ghcr.io/astral-sh/uv:python3.11-alpine
|
||||
FROM python:3.13-slim
|
||||
|
||||
# Install system dependencies required for secp256k1
|
||||
RUN apk add --no-cache \
|
||||
pkgconf \
|
||||
build-base \
|
||||
automake \
|
||||
# Install system dependencies required for secp256k1 and git
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential \
|
||||
pkg-config \
|
||||
autoconf \
|
||||
automake \
|
||||
libtool \
|
||||
m4 \
|
||||
perl
|
||||
RUN apk add git
|
||||
cmake \
|
||||
git \
|
||||
libffi-dev \
|
||||
libssl-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY uv.lock pyproject.toml ./
|
||||
|
||||
RUN uv add git+https://github.com/saschanaz/secp256k1-py.git#branch=upgrade060
|
||||
# RUN uv sync
|
||||
# Install uv
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy dependency files
|
||||
COPY uv.lock pyproject.toml ./
|
||||
|
||||
# Install dependencies
|
||||
RUN uv sync --frozen
|
||||
|
||||
# Copy application code
|
||||
COPY . .
|
||||
|
||||
# Set environment variables
|
||||
ENV PORT=8000
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["/.venv/bin/fastapi", "run", "router", "--host", "0.0.0.0"]
|
||||
# Run the application
|
||||
CMD ["uv", "run", "fastapi", "run", "router", "--host", "0.0.0.0"]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
import os
|
||||
from typing import Mapping, Optional
|
||||
|
||||
from fastapi import HTTPException, Response
|
||||
|
||||
@@ -96,7 +97,7 @@ def check_token_balance(headers: dict, body: dict, max_cost_for_model: int) -> N
|
||||
token_obj.amount if token_obj.unit == "msat" else token_obj.amount * 1000
|
||||
)
|
||||
|
||||
if max_cost_for_model > amount_msat:
|
||||
if max_cost_for_model - 100 > amount_msat:
|
||||
raise HTTPException(
|
||||
status_code=413,
|
||||
detail={
|
||||
@@ -153,7 +154,9 @@ def get_max_cost_for_model(model: str) -> int:
|
||||
return COST_PER_REQUEST
|
||||
|
||||
|
||||
def create_error_response(error_type: str, message: str, status_code: int) -> Response:
|
||||
def create_error_response(
|
||||
error_type: str, message: str, status_code: int, token: Optional[str] = None
|
||||
) -> Response:
|
||||
"""Create a standardized error response."""
|
||||
logger.info(
|
||||
"Creating error response",
|
||||
@@ -164,6 +167,9 @@ def create_error_response(error_type: str, message: str, status_code: int) -> Re
|
||||
},
|
||||
)
|
||||
|
||||
response_headers = {}
|
||||
if token:
|
||||
response_headers["X-Cashu"] = token
|
||||
return Response(
|
||||
content=json.dumps(
|
||||
{
|
||||
@@ -176,6 +182,7 @@ def create_error_response(error_type: str, message: str, status_code: int) -> Re
|
||||
),
|
||||
status_code=status_code,
|
||||
media_type="application/json",
|
||||
headers=dict(response_headers),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -125,5 +125,6 @@ async def update_sats_pricing() -> None:
|
||||
|
||||
|
||||
@models_router.get("/v1/models")
|
||||
@models_router.get("/models")
|
||||
async def models() -> dict:
|
||||
return {"data": MODELS}
|
||||
|
||||
@@ -8,12 +8,7 @@ from fastapi.responses import Response, StreamingResponse
|
||||
|
||||
from ..core import get_logger
|
||||
from ..wallet import CurrencyUnit, recieve_token, send_token
|
||||
from .cost_caculation import (
|
||||
CostData,
|
||||
CostDataError,
|
||||
MaxCostData,
|
||||
calculate_cost,
|
||||
)
|
||||
from .cost_caculation import CostData, CostDataError, MaxCostData, calculate_cost
|
||||
from .helpers import (
|
||||
UPSTREAM_BASE_URL,
|
||||
create_error_response,
|
||||
@@ -68,21 +63,30 @@ async def x_cashu_handler(
|
||||
"token_already_spent",
|
||||
"The provided CASHU token has already been spent",
|
||||
400,
|
||||
x_cashu_token,
|
||||
)
|
||||
elif "invalid token" in error_message.lower():
|
||||
|
||||
if "invalid token" in error_message.lower():
|
||||
return create_error_response(
|
||||
"invalid_token", "The provided CASHU token is invalid", 400
|
||||
"invalid_token",
|
||||
"The provided CASHU token is invalid",
|
||||
400,
|
||||
x_cashu_token,
|
||||
)
|
||||
elif "mint error" in error_message.lower():
|
||||
|
||||
if "mint error" in error_message.lower():
|
||||
return create_error_response(
|
||||
"mint_error", f"CASHU mint error: {error_message}", 422
|
||||
)
|
||||
else:
|
||||
# Generic error for other cases
|
||||
return create_error_response(
|
||||
"cashu_error", f"CASHU token processing failed: {error_message}", 400
|
||||
"mint_error", f"CASHU mint error: {error_message}", 422, x_cashu_token
|
||||
)
|
||||
|
||||
# Generic error for other cases
|
||||
return create_error_response(
|
||||
"cashu_error",
|
||||
f"CASHU token processing failed: {error_message}",
|
||||
400,
|
||||
x_cashu_token,
|
||||
)
|
||||
|
||||
|
||||
async def forward_to_upstream(
|
||||
request: Request, path: str, headers: dict, amount: int, unit: CurrencyUnit
|
||||
|
||||
@@ -2,7 +2,7 @@ import os
|
||||
from typing import Literal
|
||||
|
||||
from cashu.core.base import Token
|
||||
from cashu.wallet.helpers import deserialize_token_from_string, send
|
||||
from cashu.wallet.helpers import deserialize_token_from_string, receive, send
|
||||
from cashu.wallet.wallet import Wallet
|
||||
|
||||
from .core import db, get_logger
|
||||
@@ -29,6 +29,7 @@ async def get_balance(unit: CurrencyUnit) -> int:
|
||||
async def recieve_token(
|
||||
token: str,
|
||||
) -> tuple[int, CurrencyUnit, str]: # amount, unit, mint_url
|
||||
print(token)
|
||||
token_obj = deserialize_token_from_string(token)
|
||||
if len(token_obj.keysets) > 1:
|
||||
raise ValueError("Multiple keysets per token currently not supported")
|
||||
@@ -39,12 +40,13 @@ async def recieve_token(
|
||||
load_all_keysets=True,
|
||||
unit=token_obj.unit,
|
||||
)
|
||||
|
||||
await wallet.load_mint(token_obj.keysets[0])
|
||||
|
||||
if token_obj.mint not in TRUSTED_MINTS:
|
||||
return await swap_to_primary_mint(token_obj, wallet)
|
||||
|
||||
await wallet.redeem(token_obj.proofs)
|
||||
await receive(wallet, token_obj)
|
||||
return token_obj.amount, token_obj.unit, token_obj.mint
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user