diff --git a/app/api/routes/api.py b/app/api/routes/api.py index 0bccf5d..efe2a21 100644 --- a/app/api/routes/api.py +++ b/app/api/routes/api.py @@ -7,6 +7,8 @@ from app.schemas.dtos import ( TokenResponse, AccountBalanceDTO, LedgerEntryDTO, + CreateMarketMetadataRequest, + ResolveMarketRequest, MarketDTO, CreateOrderRequest, OrderDTO @@ -24,6 +26,39 @@ async def login_with_wallet(req: UserAuthRequest, session: AsyncSession = Depend return TokenResponse(access_token=token, address=req.address.lower()) # ================= Market Routes ================= +@api_router.post("/markets/metadata", response_model=MarketDTO) +async def create_market_metadata( + req: CreateMarketMetadataRequest, + current_user: str = Depends(get_current_user), + session: AsyncSession = Depends(get_db_session) +): + """保存预测市场的链下元数据 (标题, 描述, 类别, 2~255个选项)""" + market_service = MarketService(session) + market = await market_service.save_market_metadata( + market_address=req.market_address, + question_id=req.question_id, + title=req.title, + description=req.description, + category=req.category, + outcomes=req.outcomes, + resolution_time=req.resolution_time, + creator=current_user + ) + return MarketDTO( + market_address=market.market_address, + question_id=market.question_id, + title=market.title, + description=market.description, + category=market.category, + tier=market.tier, + creator=market.creator, + status=market.status.value if hasattr(market.status, 'value') else str(market.status), + outcomes=market.outcomes, + winning_outcome=market.winning_outcome, + resolution_time=market.resolution_time, + created_at=market.created_at + ) + @api_router.get("/markets", response_model=List[MarketDTO]) async def get_markets( category: Optional[str] = None, diff --git a/app/domains/trading/service.py b/app/domains/trading/service.py index 9bbc2af..687687c 100644 --- a/app/domains/trading/service.py +++ b/app/domains/trading/service.py @@ -12,6 +12,38 @@ class MarketService: def __init__(self, session: AsyncSession): self.session = session + async def save_market_metadata( + self, + market_address: str, + question_id: str, + title: str, + description: Optional[str], + category: str, + outcomes: List[str], + resolution_time, + creator: str + ) -> MarketModel: + market = MarketModel( + market_address=market_address.lower(), + question_id=question_id.lower(), + title=title, + description=description, + category=category or "Others", + tier=1, + creator=creator.lower(), + curve_address="0xF0E189974c413506098AFB6Bc6Bf4C6715fBf7B1", + collateral_address="0xe776e957953EA69b7Eaa9d7d4098aBC076bDD5E7", + fee_rate=Decimal("0.006"), + resolution_time=resolution_time, + outcomes=outcomes, + num_outcomes=len(outcomes), + status=MarketStatus.ACTIVE, + created_at_block=0 + ) + self.session.add(market) + await self.session.flush() + return market + async def list_markets(self, category: Optional[str] = None, status: Optional[str] = None) -> List[MarketModel]: stmt = select(MarketModel) if category: diff --git a/app/schemas/dtos.py b/app/schemas/dtos.py index 525035d..00a19c5 100644 --- a/app/schemas/dtos.py +++ b/app/schemas/dtos.py @@ -28,13 +28,15 @@ class LedgerEntryDTO(BaseModel): related_market: Optional[str] = None created_at: datetime -class CreateMarketRequest(BaseModel): +class CreateMarketMetadataRequest(BaseModel): + market_address: str + question_id: str title: str description: Optional[str] = None - category: str = "Crypto" - tier: int = 1 + category: str = "Others" # 默认 Others,支持用户自定义 + outcomes: List[str] = Field(..., min_length=2, max_length=255) # 支持最多 255 个选项 resolution_time: datetime - outcomes: List[str] = Field(..., min_length=2, max_length=8) + creator: str class MarketDTO(BaseModel): market_address: str @@ -50,10 +52,15 @@ class MarketDTO(BaseModel): resolution_time: datetime created_at: datetime +class ResolveMarketRequest(BaseModel): + market_address: str + question_id: str + winning_outcome_index: int = Field(..., ge=0, le=255) + class CreateOrderRequest(BaseModel): market_address: str vault_address: Optional[str] = None - outcome_index: int = Field(..., ge=0, le=7) + outcome_index: int = Field(..., ge=0, le=255) side: str = Field(..., pattern="^(BUY|SELL)$") amount: Decimal = Field(..., gt=0) price: Optional[Decimal] = None