from typing import Any, Dict, List, Optional, Union from pydantic import BaseModel, Field, root_validator from .base import ( BlindedMessage, BlindedMessage_Deprecated, BlindedSignature, MeltQuote, MintQuote, Proof, ProofState, ) from .settings import settings # ------- API ------- # ------- API: INFO ------- class MintMethodSetting(BaseModel): method: str unit: str min_amount: Optional[int] = None max_amount: Optional[int] = None description: Optional[bool] = None class MeltMethodSetting(BaseModel): method: str unit: str min_amount: Optional[int] = None max_amount: Optional[int] = None class MintInfoContact(BaseModel): method: str info: str class GetInfoResponse(BaseModel): name: Optional[str] = None pubkey: Optional[str] = None version: Optional[str] = None description: Optional[str] = None description_long: Optional[str] = None contact: Optional[List[MintInfoContact]] = None motd: Optional[str] = None icon_url: Optional[str] = None urls: Optional[List[str]] = None time: Optional[int] = None nuts: Optional[Dict[int, Any]] = None def supports(self, nut: int) -> Optional[bool]: return nut in self.nuts if self.nuts else None # BEGIN DEPRECATED: NUT-06 contact field change # NUT-06 PR: https://github.com/cashubtc/nuts/pull/117 @root_validator(pre=True) def preprocess_deprecated_contact_field(cls, values): if "contact" in values and values["contact"]: if isinstance(values["contact"][0], list): values["contact"] = [ MintInfoContact(method=method, info=info) for method, info in values["contact"] if method and info ] return values # END DEPRECATED: NUT-06 contact field change class Nut15MppSupport(BaseModel): method: str unit: str class GetInfoResponse_deprecated(BaseModel): name: Optional[str] = None pubkey: Optional[str] = None version: Optional[str] = None description: Optional[str] = None description_long: Optional[str] = None contact: Optional[List[List[str]]] = None nuts: Optional[List[str]] = None motd: Optional[str] = None parameter: Optional[dict] = None # ------- API: KEYS ------- class KeysResponseKeyset(BaseModel): id: str unit: str keys: Dict[int, str] class KeysResponse(BaseModel): keysets: List[KeysResponseKeyset] class KeysetsResponseKeyset(BaseModel): id: str unit: str active: bool input_fee_ppk: Optional[int] = None class KeysetsResponse(BaseModel): keysets: list[KeysetsResponseKeyset] class KeysResponse_deprecated(BaseModel): __root__: Dict[str, str] class KeysetsResponse_deprecated(BaseModel): keysets: list[str] # ------- API: MINT QUOTE ------- class PostMintQuoteRequest(BaseModel): unit: str = Field(..., max_length=settings.mint_max_request_length) # output unit amount: int = Field(..., gt=0) # output amount description: Optional[str] = Field( default=None, max_length=settings.mint_max_request_length ) # invoice description pubkey: Optional[str] = Field( default=None, max_length=settings.mint_max_request_length ) # NUT-20 quote lock pubkey class PostMintQuoteResponse(BaseModel): quote: str # quote id request: str # input payment request state: Optional[str] # state of the quote (optional for backwards compat) expiry: Optional[int] # expiry of the quote pubkey: Optional[str] = None # NUT-20 quote lock pubkey paid: Optional[bool] = None # DEPRECATED as per NUT-04 PR #141 @classmethod def from_mint_quote(cls, mint_quote: MintQuote) -> "PostMintQuoteResponse": to_dict = mint_quote.dict() # turn state into string to_dict["state"] = mint_quote.state.value return cls.parse_obj(to_dict) # ------- API: MINT ------- class PostMintRequest(BaseModel): quote: str = Field(..., max_length=settings.mint_max_request_length) # quote id outputs: List[BlindedMessage] = Field( ..., max_items=settings.mint_max_request_length ) signature: Optional[str] = Field( default=None, max_length=settings.mint_max_request_length ) # NUT-20 quote signature class PostMintResponse(BaseModel): signatures: List[BlindedSignature] = [] class GetMintResponse_deprecated(BaseModel): pr: str hash: str class PostMintRequest_deprecated(BaseModel): outputs: List[BlindedMessage_Deprecated] = Field( ..., max_items=settings.mint_max_request_length ) class PostMintResponse_deprecated(BaseModel): promises: List[BlindedSignature] = [] # ------- API: MELT QUOTE ------- class PostMeltRequestOptionMpp(BaseModel): amount: int = Field(gt=0) # input amount class PostMeltRequestOptions(BaseModel): mpp: Optional[PostMeltRequestOptionMpp] class PostMeltQuoteRequest(BaseModel): unit: str = Field(..., max_length=settings.mint_max_request_length) # input unit request: str = Field( ..., max_length=settings.mint_max_request_length ) # output payment request options: Optional[PostMeltRequestOptions] = None @property def is_mpp(self) -> bool: if self.options and self.options.mpp: return True else: return False @property def mpp_amount(self) -> int: if self.is_mpp and self.options and self.options.mpp: return self.options.mpp.amount else: raise Exception("quote request is not mpp.") class PostMeltQuoteResponse(BaseModel): quote: str # quote id amount: int # input amount fee_reserve: int # input fee reserve paid: Optional[bool] = ( None # whether the request has been paid # DEPRECATED as per NUT PR #136 ) state: Optional[str] # state of the quote expiry: Optional[int] # expiry of the quote payment_preimage: Optional[str] = None # payment preimage change: Union[List[BlindedSignature], None] = None # NUT-08 change @classmethod def from_melt_quote(self, melt_quote: MeltQuote) -> "PostMeltQuoteResponse": to_dict = melt_quote.dict() # turn state into string to_dict["state"] = melt_quote.state.value # add deprecated "paid" field to_dict["paid"] = melt_quote.paid return PostMeltQuoteResponse.parse_obj(to_dict) # ------- API: MELT ------- class PostMeltRequest(BaseModel): quote: str = Field(..., max_length=settings.mint_max_request_length) # quote id inputs: List[Proof] = Field(..., max_items=settings.mint_max_request_length) outputs: Union[List[BlindedMessage], None] = Field( None, max_items=settings.mint_max_request_length ) class PostMeltResponse_deprecated(BaseModel): paid: Union[bool, None] preimage: Union[str, None] change: Union[List[BlindedSignature], None] = None class PostMeltRequest_deprecated(BaseModel): proofs: List[Proof] = Field(..., max_items=settings.mint_max_request_length) pr: str = Field(..., max_length=settings.mint_max_request_length) outputs: Union[List[BlindedMessage_Deprecated], None] = Field( None, max_items=settings.mint_max_request_length ) # ------- API: SPLIT ------- class PostSwapRequest(BaseModel): inputs: List[Proof] = Field(..., max_items=settings.mint_max_request_length) outputs: List[BlindedMessage] = Field( ..., max_items=settings.mint_max_request_length ) class PostSwapResponse(BaseModel): signatures: List[BlindedSignature] # deprecated since 0.13.0 class PostSwapRequest_Deprecated(BaseModel): proofs: List[Proof] = Field(..., max_items=settings.mint_max_request_length) amount: Optional[int] = None outputs: List[BlindedMessage_Deprecated] = Field( ..., max_items=settings.mint_max_request_length ) class PostSwapResponse_Deprecated(BaseModel): promises: List[BlindedSignature] = [] class PostSwapResponse_Very_Deprecated(BaseModel): fst: List[BlindedSignature] = [] snd: List[BlindedSignature] = [] deprecated: str = "The amount field is deprecated since 0.13.0" # ------- API: CHECK ------- class PostCheckStateRequest(BaseModel): Ys: List[str] = Field(..., max_items=settings.mint_max_request_length) class PostCheckStateResponse(BaseModel): states: List[ProofState] = [] class CheckSpendableRequest_deprecated(BaseModel): proofs: List[Proof] = Field(..., max_items=settings.mint_max_request_length) class CheckSpendableResponse_deprecated(BaseModel): spendable: List[bool] pending: List[bool] class CheckFeesRequest_deprecated(BaseModel): pr: str = Field(..., max_length=settings.mint_max_request_length) class CheckFeesResponse_deprecated(BaseModel): fee: Union[int, None] # ------- API: RESTORE ------- class PostRestoreRequest(BaseModel): outputs: List[BlindedMessage] = Field( ..., max_items=settings.mint_max_request_length ) class PostRestoreRequest_Deprecated(BaseModel): outputs: List[BlindedMessage_Deprecated] = Field( ..., max_items=settings.mint_max_request_length ) class PostRestoreResponse(BaseModel): outputs: List[BlindedMessage] = [] signatures: List[BlindedSignature] = [] promises: Optional[List[BlindedSignature]] = [] # deprecated since 0.15.1 # duplicate value of "signatures" for backwards compatibility with old clients < 0.15.1 def __init__(self, **data): super().__init__(**data) self.promises = self.signatures