diff options
| author | Tolmachev Igor <me@igorek.dev> | 2025-07-17 15:18:44 +0900 |
|---|---|---|
| committer | Tolmachev Igor <me@igorek.dev> | 2025-07-17 15:31:54 +0900 |
| commit | 166b2faed2ee31970ca77f03d0c2095b3482ad26 (patch) | |
| tree | 51cc5ea76ef9c64672ff5b231890b9512c8e21e4 /src | |
| parent | 69296e9899d28a6a5e64708cbcdc57a59a54fa41 (diff) | |
| download | async_crypto_pay_api-166b2faed2ee31970ca77f03d0c2095b3482ad26.tar.gz async_crypto_pay_api-166b2faed2ee31970ca77f03d0c2095b3482ad26.zip | |
Release v.1.0.0
Diffstat (limited to 'src')
| -rw-r--r-- | src/async_crypto_pay_api/__init__.py | 16 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/__meta__.py | 2 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/client.py | 371 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/exceptions.py | 26 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/models/__init__.py | 52 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/models/app_info.py | 14 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/models/app_stats.py | 19 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/models/assets.py | 73 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/models/balance.py | 16 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/models/check.py | 26 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/models/currency.py | 18 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/models/exchange_rate.py | 19 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/models/invoice.py | 82 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/models/items.py | 14 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/models/response.py | 22 | ||||
| -rw-r--r-- | src/async_crypto_pay_api/models/transfer.py | 23 |
16 files changed, 793 insertions, 0 deletions
diff --git a/src/async_crypto_pay_api/__init__.py b/src/async_crypto_pay_api/__init__.py new file mode 100644 index 0000000..8689f7f --- /dev/null +++ b/src/async_crypto_pay_api/__init__.py | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | # TODO: Add doc strings | ||
| 2 | # TODO: Add webhooks | ||
| 3 | |||
| 4 | # isort: off | ||
| 5 | from . import models | ||
| 6 | from . import exceptions | ||
| 7 | from . import client | ||
| 8 | |||
| 9 | from .client import CryptoPayApi | ||
| 10 | |||
| 11 | __all__ = [ | ||
| 12 | "models", | ||
| 13 | "exceptions", | ||
| 14 | "client", | ||
| 15 | "CryptoPayApi", | ||
| 16 | ] | ||
diff --git a/src/async_crypto_pay_api/__meta__.py b/src/async_crypto_pay_api/__meta__.py new file mode 100644 index 0000000..d53578f --- /dev/null +++ b/src/async_crypto_pay_api/__meta__.py | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | __version__ = "1.0.0" | ||
| 2 | __api_version__ = "1.5.1" | ||
diff --git a/src/async_crypto_pay_api/client.py b/src/async_crypto_pay_api/client.py new file mode 100644 index 0000000..93551fd --- /dev/null +++ b/src/async_crypto_pay_api/client.py | |||
| @@ -0,0 +1,371 @@ | |||
| 1 | from datetime import datetime, timedelta | ||
| 2 | from decimal import Decimal | ||
| 3 | from enum import Enum | ||
| 4 | from secrets import token_hex | ||
| 5 | from typing import Any, Literal, TypeVar, overload | ||
| 6 | |||
| 7 | from aiohttp import ClientSession | ||
| 8 | from pydantic import ValidationError | ||
| 9 | |||
| 10 | from async_crypto_pay_api import models as m | ||
| 11 | from async_crypto_pay_api.exceptions import InvalidResponseError, RequestError | ||
| 12 | |||
| 13 | |||
| 14 | def serialize_value(value: Any) -> str: | ||
| 15 | if isinstance(value, str): | ||
| 16 | return value | ||
| 17 | elif isinstance(value, (int, float, Decimal)): | ||
| 18 | return str(value) | ||
| 19 | elif isinstance(value, bool): | ||
| 20 | return "true" if value else "false" | ||
| 21 | elif isinstance(value, list): | ||
| 22 | return ",".join(map(serialize_value, value)) | ||
| 23 | elif isinstance(value, datetime): | ||
| 24 | return value.isoformat() | ||
| 25 | elif isinstance(value, Enum): | ||
| 26 | return value.value | ||
| 27 | else: | ||
| 28 | raise ValueError(f"unsupported type for serialization: '{type(value)}'") | ||
| 29 | |||
| 30 | |||
| 31 | def serialize_body(body: dict[str, Any]) -> dict[str, Any]: | ||
| 32 | return {k: serialize_value(v) for k, v in body.items() if v is not None} | ||
| 33 | |||
| 34 | |||
| 35 | R = TypeVar("R") | ||
| 36 | |||
| 37 | |||
| 38 | class CryptoPayApi: | ||
| 39 | __token: str | ||
| 40 | __is_test_backend: bool | ||
| 41 | __session: ClientSession | None | ||
| 42 | |||
| 43 | def __init__(self, token: str, test_backend: bool = False) -> None: | ||
| 44 | self.__token = token | ||
| 45 | self.__is_test_backend = test_backend | ||
| 46 | self.__session = None | ||
| 47 | |||
| 48 | async def __aenter__(self) -> "CryptoPayApi": | ||
| 49 | self.__get_session() | ||
| 50 | return self | ||
| 51 | |||
| 52 | async def __aexit__(self, *_) -> bool: | ||
| 53 | await self.close() | ||
| 54 | return False | ||
| 55 | |||
| 56 | def __get_session(self) -> ClientSession: | ||
| 57 | if self.__session is None: | ||
| 58 | self.__session = ClientSession( | ||
| 59 | base_url=( | ||
| 60 | "https://testnet-pay.crypt.bot/api/" | ||
| 61 | if self.__is_test_backend | ||
| 62 | else "https://pay.crypt.bot/api/" | ||
| 63 | ), | ||
| 64 | headers={"Crypto-Pay-API-Token": self.__token}, | ||
| 65 | ) | ||
| 66 | |||
| 67 | return self.__session | ||
| 68 | |||
| 69 | async def __process_request( | ||
| 70 | self, | ||
| 71 | method_name: str, | ||
| 72 | result_model: type[R], | ||
| 73 | body: dict[str, Any] | None = None, | ||
| 74 | ) -> R: | ||
| 75 | async with ( | ||
| 76 | self.__get_session().post( | ||
| 77 | method_name, | ||
| 78 | json={} if body is None else body, | ||
| 79 | ) as http_response, | ||
| 80 | ): | ||
| 81 | json = await http_response.json() | ||
| 82 | try: | ||
| 83 | response = m.Response[result_model].model_validate(json) | ||
| 84 | except ValidationError: | ||
| 85 | raise InvalidResponseError("invalid response body") | ||
| 86 | |||
| 87 | if response.ok: | ||
| 88 | if response.result is None: | ||
| 89 | raise InvalidResponseError( | ||
| 90 | "response.result is empty while response.ok = True" | ||
| 91 | ) | ||
| 92 | |||
| 93 | return response.result | ||
| 94 | else: | ||
| 95 | if response.error is None: | ||
| 96 | raise InvalidResponseError( | ||
| 97 | "response.error is empty while response.ok = False" | ||
| 98 | ) | ||
| 99 | |||
| 100 | raise RequestError(response.error.code, response.error.name) | ||
| 101 | |||
| 102 | @property | ||
| 103 | def token(self) -> str: | ||
| 104 | return self.__token | ||
| 105 | |||
| 106 | async def close(self) -> None: | ||
| 107 | if self.__session is None: | ||
| 108 | return | ||
| 109 | |||
| 110 | await self.__session.close() | ||
| 111 | self.__session = None | ||
| 112 | |||
| 113 | async def get_me(self) -> m.AppInfo: | ||
| 114 | return await self.__process_request("getMe", result_model=m.AppInfo) | ||
| 115 | |||
| 116 | @overload | ||
| 117 | async def create_invoice( | ||
| 118 | self, | ||
| 119 | *, | ||
| 120 | currency_type: Literal[m.CurrencyType.CRYPTO], | ||
| 121 | asset: m.CryptoAsset, | ||
| 122 | amount: int | float | Decimal, | ||
| 123 | swap_to: m.SwapAsset | None = None, | ||
| 124 | description: str | None = None, | ||
| 125 | hidden_message: str | None = None, | ||
| 126 | paid_btn_name: None = None, | ||
| 127 | paid_btn_url: None = None, | ||
| 128 | payload: str | None = None, | ||
| 129 | allow_comments: bool = True, | ||
| 130 | allow_anonymous: bool = True, | ||
| 131 | expires_in: timedelta | None = None, | ||
| 132 | ) -> m.Invoice: ... | ||
| 133 | |||
| 134 | @overload | ||
| 135 | async def create_invoice( | ||
| 136 | self, | ||
| 137 | *, | ||
| 138 | currency_type: Literal[m.CurrencyType.CRYPTO], | ||
| 139 | asset: m.CryptoAsset, | ||
| 140 | amount: int | float | Decimal, | ||
| 141 | paid_btn_name: m.PaidButtonName, | ||
| 142 | paid_btn_url: str, | ||
| 143 | swap_to: m.SwapAsset | None = None, | ||
| 144 | description: str | None = None, | ||
| 145 | hidden_message: str | None = None, | ||
| 146 | payload: str | None = None, | ||
| 147 | allow_comments: bool = True, | ||
| 148 | allow_anonymous: bool = True, | ||
| 149 | expires_in: timedelta | None = None, | ||
| 150 | ) -> m.Invoice: ... | ||
| 151 | |||
| 152 | @overload | ||
| 153 | async def create_invoice( | ||
| 154 | self, | ||
| 155 | *, | ||
| 156 | currency_type: Literal[m.CurrencyType.FIAT], | ||
| 157 | fiat: m.FiatAsset, | ||
| 158 | accepted_assets: list[m.CryptoAsset] | None = None, | ||
| 159 | amount: int | float | Decimal, | ||
| 160 | swap_to: m.SwapAsset | None = None, | ||
| 161 | description: str | None = None, | ||
| 162 | hidden_message: str | None = None, | ||
| 163 | paid_btn_name: None = None, | ||
| 164 | paid_btn_url: None = None, | ||
| 165 | payload: str | None = None, | ||
| 166 | allow_comments: bool = True, | ||
| 167 | allow_anonymous: bool = True, | ||
| 168 | expires_in: timedelta | None = None, | ||
| 169 | ) -> m.Invoice: ... | ||
| 170 | |||
| 171 | @overload | ||
| 172 | async def create_invoice( | ||
| 173 | self, | ||
| 174 | *, | ||
| 175 | currency_type: Literal[m.CurrencyType.FIAT], | ||
| 176 | fiat: m.FiatAsset, | ||
| 177 | amount: int | float | Decimal, | ||
| 178 | paid_btn_name: m.PaidButtonName, | ||
| 179 | paid_btn_url: str, | ||
| 180 | accepted_assets: list[m.CryptoAsset] | None = None, | ||
| 181 | swap_to: m.SwapAsset | None = None, | ||
| 182 | description: str | None = None, | ||
| 183 | hidden_message: str | None = None, | ||
| 184 | payload: str | None = None, | ||
| 185 | allow_comments: bool = True, | ||
| 186 | allow_anonymous: bool = True, | ||
| 187 | expires_in: timedelta | None = None, | ||
| 188 | ) -> m.Invoice: ... | ||
| 189 | |||
| 190 | async def create_invoice(self, **body: Any) -> m.Invoice: | ||
| 191 | return await self.__process_request( | ||
| 192 | "createInvoice", | ||
| 193 | result_model=m.Invoice, | ||
| 194 | body=serialize_body(body), | ||
| 195 | ) | ||
| 196 | |||
| 197 | async def delete_invoice(self, invoice_id: int) -> bool: | ||
| 198 | return await self.__process_request( | ||
| 199 | "deleteInvoice", | ||
| 200 | result_model=bool, | ||
| 201 | body=serialize_body(dict(invoice_id=invoice_id)), | ||
| 202 | ) | ||
| 203 | |||
| 204 | async def create_check( | ||
| 205 | self, | ||
| 206 | *, | ||
| 207 | asset: m.CryptoAsset, | ||
| 208 | amount: int | float | Decimal, | ||
| 209 | pin_to_user_id: int | None = None, | ||
| 210 | pin_to_username: str | None = None, | ||
| 211 | ) -> m.Check: | ||
| 212 | return await self.__process_request( | ||
| 213 | "createCheck", | ||
| 214 | result_model=m.Check, | ||
| 215 | body=serialize_body( | ||
| 216 | dict( | ||
| 217 | asset=asset, | ||
| 218 | amount=amount, | ||
| 219 | pin_to_user_id=pin_to_user_id, | ||
| 220 | pin_to_username=pin_to_username, | ||
| 221 | ) | ||
| 222 | ), | ||
| 223 | ) | ||
| 224 | |||
| 225 | async def delete_check(self, check_id: int) -> bool: | ||
| 226 | return await self.__process_request( | ||
| 227 | "deleteCheck", | ||
| 228 | result_model=bool, | ||
| 229 | body=serialize_body(dict(check_id=check_id)), | ||
| 230 | ) | ||
| 231 | |||
| 232 | async def transfer( | ||
| 233 | self, | ||
| 234 | *, | ||
| 235 | user_id: int, | ||
| 236 | asset: m.CryptoAsset, | ||
| 237 | amount: int | float | Decimal, | ||
| 238 | comment: str | None = None, | ||
| 239 | disable_send_notification: bool = False, | ||
| 240 | ) -> m.Transfer: | ||
| 241 | return await self.__process_request( | ||
| 242 | "transfer", | ||
| 243 | m.Transfer, | ||
| 244 | body=serialize_body( | ||
| 245 | dict( | ||
| 246 | user_id=user_id, | ||
| 247 | asset=asset, | ||
| 248 | amount=amount, | ||
| 249 | spend_id=token_hex(32), | ||
| 250 | comment=comment, | ||
| 251 | disable_send_notification=disable_send_notification, | ||
| 252 | ) | ||
| 253 | ), | ||
| 254 | ) | ||
| 255 | |||
| 256 | @overload | ||
| 257 | async def get_invoices( | ||
| 258 | self, | ||
| 259 | *, | ||
| 260 | asset: m.CryptoAsset, | ||
| 261 | invoice_ids: list[int] | None = None, | ||
| 262 | status: m.InvoiceSearchStatus | None = None, | ||
| 263 | offset: int = 0, | ||
| 264 | count: int = 100, | ||
| 265 | ) -> list[m.Invoice]: ... | ||
| 266 | |||
| 267 | @overload | ||
| 268 | async def get_invoices( | ||
| 269 | self, | ||
| 270 | *, | ||
| 271 | fiat: m.FiatAsset, | ||
| 272 | invoice_ids: list[int] | None = None, | ||
| 273 | status: m.InvoiceSearchStatus | None = None, | ||
| 274 | offset: int = 0, | ||
| 275 | count: int = 100, | ||
| 276 | ) -> list[m.Invoice]: ... | ||
| 277 | |||
| 278 | @overload | ||
| 279 | async def get_invoices( | ||
| 280 | self, | ||
| 281 | *, | ||
| 282 | asset: None = None, | ||
| 283 | fiat: None = None, | ||
| 284 | invoice_ids: list[int] | None = None, | ||
| 285 | status: m.InvoiceSearchStatus | None = None, | ||
| 286 | offset: int = 0, | ||
| 287 | count: int = 100, | ||
| 288 | ) -> list[m.Invoice]: ... | ||
| 289 | |||
| 290 | async def get_invoices(self, **body: Any) -> list[m.Invoice]: | ||
| 291 | items = await self.__process_request( | ||
| 292 | "getInvoices", | ||
| 293 | m.Items[m.Invoice], | ||
| 294 | serialize_body(body), | ||
| 295 | ) | ||
| 296 | return items.items | ||
| 297 | |||
| 298 | async def get_transfers( | ||
| 299 | self, | ||
| 300 | asset: m.CryptoAsset | None = None, | ||
| 301 | transfer_ids: list[int] | None = None, | ||
| 302 | offset: int = 0, | ||
| 303 | count: int = 100, | ||
| 304 | ) -> list[m.Transfer]: | ||
| 305 | items = await self.__process_request( | ||
| 306 | "getTransfers", | ||
| 307 | m.Items[m.Transfer], | ||
| 308 | serialize_body( | ||
| 309 | dict( | ||
| 310 | asset=asset, | ||
| 311 | transfer_ids=transfer_ids, | ||
| 312 | offset=offset, | ||
| 313 | count=count, | ||
| 314 | ) | ||
| 315 | ), | ||
| 316 | ) | ||
| 317 | return items.items | ||
| 318 | |||
| 319 | async def get_checks( | ||
| 320 | self, | ||
| 321 | asset: m.CryptoAsset | None = None, | ||
| 322 | check_ids: list[int] | None = None, | ||
| 323 | status: m.CheckStatus | None = None, | ||
| 324 | offset: int = 0, | ||
| 325 | count: int = 100, | ||
| 326 | ) -> list[m.Check]: | ||
| 327 | items = await self.__process_request( | ||
| 328 | "getChecks", | ||
| 329 | m.Items[m.Check], | ||
| 330 | serialize_body( | ||
| 331 | dict( | ||
| 332 | asset=asset, | ||
| 333 | check_ids=check_ids, | ||
| 334 | status=status, | ||
| 335 | offset=offset, | ||
| 336 | count=count, | ||
| 337 | ) | ||
| 338 | ), | ||
| 339 | ) | ||
| 340 | return items.items | ||
| 341 | |||
| 342 | async def get_balance(self) -> list[m.Balance]: | ||
| 343 | return await self.__process_request("getBalance", list[m.Balance]) | ||
| 344 | |||
| 345 | async def get_exchange_rates(self) -> list[m.ExchangeRate]: | ||
| 346 | return await self.__process_request("getExchangeRates", list[m.ExchangeRate]) | ||
| 347 | |||
| 348 | async def get_currencies(self) -> list[m.Currency]: | ||
| 349 | return await self.__process_request("getCurrencies", list[m.Currency]) | ||
| 350 | |||
| 351 | async def get_stats( | ||
| 352 | self, | ||
| 353 | *, | ||
| 354 | start_at: datetime | None = None, | ||
| 355 | end_at: datetime | None = None, | ||
| 356 | ) -> m.AppStats: | ||
| 357 | return await self.__process_request( | ||
| 358 | "getStats", | ||
| 359 | m.AppStats, | ||
| 360 | serialize_body( | ||
| 361 | dict( | ||
| 362 | start_at=start_at, | ||
| 363 | end_at=end_at, | ||
| 364 | ) | ||
| 365 | ), | ||
| 366 | ) | ||
| 367 | |||
| 368 | |||
| 369 | __all__ = [ | ||
| 370 | "CryptoPayApi", | ||
| 371 | ] | ||
diff --git a/src/async_crypto_pay_api/exceptions.py b/src/async_crypto_pay_api/exceptions.py new file mode 100644 index 0000000..a5bcf4e --- /dev/null +++ b/src/async_crypto_pay_api/exceptions.py | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | class CryptoPayError(Exception): | ||
| 2 | def __init__(self, message: str) -> None: | ||
| 3 | super().__init__(message) | ||
| 4 | |||
| 5 | |||
| 6 | class RequestError(CryptoPayError): | ||
| 7 | status_code: int | ||
| 8 | name: str | ||
| 9 | |||
| 10 | def __init__(self, status_code: int, name: str) -> None: | ||
| 11 | super().__init__(f"{name} [{status_code}]") | ||
| 12 | |||
| 13 | self.status_code = status_code | ||
| 14 | self.name = name | ||
| 15 | |||
| 16 | |||
| 17 | class InvalidResponseError(CryptoPayError): | ||
| 18 | def __init__(self, info: str) -> None: | ||
| 19 | super().__init__(f"server response is invalid: {info}") | ||
| 20 | |||
| 21 | |||
| 22 | __all__ = [ | ||
| 23 | "CryptoPayError", | ||
| 24 | "RequestError", | ||
| 25 | "InvalidResponseError", | ||
| 26 | ] | ||
diff --git a/src/async_crypto_pay_api/models/__init__.py b/src/async_crypto_pay_api/models/__init__.py new file mode 100644 index 0000000..36bde28 --- /dev/null +++ b/src/async_crypto_pay_api/models/__init__.py | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | # isort: off | ||
| 2 | from .response import Error, Response | ||
| 3 | from .app_info import AppInfo | ||
| 4 | from .items import Items | ||
| 5 | from .assets import CryptoAsset, FiatAsset, SwapAsset | ||
| 6 | from .invoice import ( | ||
| 7 | CurrencyType, | ||
| 8 | InvoiceStatus, | ||
| 9 | PaidButtonName, | ||
| 10 | Invoice, | ||
| 11 | InvoiceSearchStatus, | ||
| 12 | ) | ||
| 13 | from .check import CheckStatus, Check | ||
| 14 | from .transfer import Transfer | ||
| 15 | from .balance import Balance | ||
| 16 | from .exchange_rate import ExchangeRate | ||
| 17 | from .app_stats import AppStats | ||
| 18 | from .currency import Currency | ||
| 19 | |||
| 20 | __all__ = [ | ||
| 21 | # response | ||
| 22 | "Error", | ||
| 23 | "Response", | ||
| 24 | # app_info | ||
| 25 | "AppInfo", | ||
| 26 | # assets | ||
| 27 | "CryptoAsset", | ||
| 28 | "FiatAsset", | ||
| 29 | "SwapAsset", | ||
| 30 | # items | ||
| 31 | "Items", | ||
| 32 | # invoice, | ||
| 33 | "CurrencyType", | ||
| 34 | "InvoiceStatus", | ||
| 35 | "SwapAsset", | ||
| 36 | "PaidButtonName", | ||
| 37 | "Invoice", | ||
| 38 | "InvoiceSearchStatus", | ||
| 39 | # check | ||
| 40 | "CheckStatus", | ||
| 41 | "Check", | ||
| 42 | # transfer | ||
| 43 | "Transfer", | ||
| 44 | # balance | ||
| 45 | "Balance", | ||
| 46 | # exchange_rate | ||
| 47 | "ExchangeRate", | ||
| 48 | # currency | ||
| 49 | "Currency", | ||
| 50 | # app_stats | ||
| 51 | "AppStats", | ||
| 52 | ] | ||
diff --git a/src/async_crypto_pay_api/models/app_info.py b/src/async_crypto_pay_api/models/app_info.py new file mode 100644 index 0000000..e923212 --- /dev/null +++ b/src/async_crypto_pay_api/models/app_info.py | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | from typing import Literal | ||
| 2 | |||
| 3 | from pydantic import BaseModel | ||
| 4 | |||
| 5 | |||
| 6 | class AppInfo(BaseModel, frozen=True): | ||
| 7 | app_id: int | ||
| 8 | name: str | ||
| 9 | payment_processing_bot_username: Literal["CryptoBot", "CryptoTestnetBot"] | ||
| 10 | |||
| 11 | |||
| 12 | __all__ = [ | ||
| 13 | "AppInfo", | ||
| 14 | ] | ||
diff --git a/src/async_crypto_pay_api/models/app_stats.py b/src/async_crypto_pay_api/models/app_stats.py new file mode 100644 index 0000000..1f98554 --- /dev/null +++ b/src/async_crypto_pay_api/models/app_stats.py | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | from datetime import datetime as Datetime | ||
| 2 | from decimal import Decimal | ||
| 3 | |||
| 4 | from pydantic import BaseModel | ||
| 5 | |||
| 6 | |||
| 7 | class AppStats(BaseModel, frozen=True): | ||
| 8 | volume: Decimal | ||
| 9 | conversion: Decimal | ||
| 10 | unique_users_count: int | ||
| 11 | created_invoice_count: int | ||
| 12 | paid_invoice_count: int | ||
| 13 | start_at: Datetime | ||
| 14 | end_at: Datetime | ||
| 15 | |||
| 16 | |||
| 17 | __all__ = [ | ||
| 18 | "AppStats", | ||
| 19 | ] | ||
diff --git a/src/async_crypto_pay_api/models/assets.py b/src/async_crypto_pay_api/models/assets.py new file mode 100644 index 0000000..2616668 --- /dev/null +++ b/src/async_crypto_pay_api/models/assets.py | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | from enum import Enum | ||
| 2 | |||
| 3 | |||
| 4 | class EnumWithUnknown(Enum): | ||
| 5 | UNKNOWN = "UNKNOWN" | ||
| 6 | |||
| 7 | |||
| 8 | class CryptoAsset(Enum): | ||
| 9 | USDT = "USDT" | ||
| 10 | TON = "TON" | ||
| 11 | SOL = "SOL" | ||
| 12 | TRX = "TRX" | ||
| 13 | GRAM = "GRAM" | ||
| 14 | BTC = "BTC" | ||
| 15 | ETH = "ETH" | ||
| 16 | DOGE = "DOGE" | ||
| 17 | LTC = "LTC" | ||
| 18 | NOT = "NOT" | ||
| 19 | TRUMP = "TRUMP" | ||
| 20 | MELANIA = "MELANIA" | ||
| 21 | PEPE = "PEPE" | ||
| 22 | WIF = "WIF" | ||
| 23 | BONK = "BONK" | ||
| 24 | MAJOR = "MAJOR" | ||
| 25 | MY = "MY" | ||
| 26 | DOGS = "DOGS" | ||
| 27 | MEMHASH = "MEMHASH" | ||
| 28 | BNB = "BNB" | ||
| 29 | HMSTR = "HMSTR" | ||
| 30 | CATI = "CATI" | ||
| 31 | USDC = "USDC" | ||
| 32 | |||
| 33 | |||
| 34 | class FiatAsset(Enum): | ||
| 35 | RUB = "RUB" | ||
| 36 | USD = "USD" | ||
| 37 | EUR = "EUR" | ||
| 38 | BYN = "BYN" | ||
| 39 | UAH = "UAH" | ||
| 40 | GBP = "GBP" | ||
| 41 | CNY = "CNY" | ||
| 42 | KZT = "KZT" | ||
| 43 | UZS = "UZS" | ||
| 44 | GEL = "GEL" | ||
| 45 | TRY = "TRY" | ||
| 46 | AMD = "AMD" | ||
| 47 | THB = "THB" | ||
| 48 | INR = "INR" | ||
| 49 | BRL = "BRL" | ||
| 50 | IDR = "IDR" | ||
| 51 | AZN = "AZN" | ||
| 52 | AED = "AED" | ||
| 53 | PLN = "PLN" | ||
| 54 | ILS = "ILS" | ||
| 55 | KGS = "KGS" | ||
| 56 | TJS = "TJS" | ||
| 57 | |||
| 58 | |||
| 59 | class SwapAsset(Enum): | ||
| 60 | USDT = "USDT" | ||
| 61 | TON = "TON" | ||
| 62 | TRX = "TRX" | ||
| 63 | ETH = "ETH" | ||
| 64 | SOL = "SOL" | ||
| 65 | BTC = "BTC" | ||
| 66 | LTC = "LTC" | ||
| 67 | |||
| 68 | |||
| 69 | __all__ = [ | ||
| 70 | "CryptoAsset", | ||
| 71 | "FiatAsset", | ||
| 72 | "SwapAsset", | ||
| 73 | ] | ||
diff --git a/src/async_crypto_pay_api/models/balance.py b/src/async_crypto_pay_api/models/balance.py new file mode 100644 index 0000000..3c64de6 --- /dev/null +++ b/src/async_crypto_pay_api/models/balance.py | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | from decimal import Decimal | ||
| 2 | |||
| 3 | from pydantic import BaseModel | ||
| 4 | |||
| 5 | from async_crypto_pay_api.models import CryptoAsset | ||
| 6 | |||
| 7 | |||
| 8 | class Balance(BaseModel, frozen=True): | ||
| 9 | currency_code: CryptoAsset | ||
| 10 | available: Decimal | ||
| 11 | onhold: Decimal | ||
| 12 | |||
| 13 | |||
| 14 | __all__ = [ | ||
| 15 | "Balance", | ||
| 16 | ] | ||
diff --git a/src/async_crypto_pay_api/models/check.py b/src/async_crypto_pay_api/models/check.py new file mode 100644 index 0000000..b8f2b7b --- /dev/null +++ b/src/async_crypto_pay_api/models/check.py | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | from datetime import datetime as Datetime | ||
| 2 | from decimal import Decimal | ||
| 3 | from enum import Enum | ||
| 4 | |||
| 5 | from pydantic import BaseModel | ||
| 6 | |||
| 7 | from async_crypto_pay_api.models import CryptoAsset | ||
| 8 | |||
| 9 | |||
| 10 | class CheckStatus(Enum): | ||
| 11 | ACTIVE = "active" | ||
| 12 | ACTIVATED = "activated" | ||
| 13 | |||
| 14 | |||
| 15 | class Check(BaseModel, frozen=True): | ||
| 16 | check_id: int | ||
| 17 | hash: str | ||
| 18 | asset: CryptoAsset | ||
| 19 | amount: Decimal | ||
| 20 | bot_check_url: str | ||
| 21 | status: CheckStatus | ||
| 22 | created_at: Datetime | ||
| 23 | activated_at: Datetime | None = None | ||
| 24 | |||
| 25 | |||
| 26 | __all__ = [] | ||
diff --git a/src/async_crypto_pay_api/models/currency.py b/src/async_crypto_pay_api/models/currency.py new file mode 100644 index 0000000..64a71a2 --- /dev/null +++ b/src/async_crypto_pay_api/models/currency.py | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | from pydantic import BaseModel | ||
| 2 | |||
| 3 | from async_crypto_pay_api.models import CryptoAsset, FiatAsset | ||
| 4 | |||
| 5 | |||
| 6 | class Currency(BaseModel, frozen=True): | ||
| 7 | is_blockchain: bool | ||
| 8 | is_stablecoin: bool | ||
| 9 | is_fiat: bool | ||
| 10 | name: str | ||
| 11 | code: CryptoAsset | FiatAsset | ||
| 12 | url: str | None = None | ||
| 13 | decimals: int | ||
| 14 | |||
| 15 | |||
| 16 | __all__ = [ | ||
| 17 | "Currency", | ||
| 18 | ] | ||
diff --git a/src/async_crypto_pay_api/models/exchange_rate.py b/src/async_crypto_pay_api/models/exchange_rate.py new file mode 100644 index 0000000..bf07719 --- /dev/null +++ b/src/async_crypto_pay_api/models/exchange_rate.py | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | from decimal import Decimal | ||
| 2 | |||
| 3 | from pydantic import BaseModel | ||
| 4 | |||
| 5 | from async_crypto_pay_api.models import CryptoAsset, FiatAsset | ||
| 6 | |||
| 7 | |||
| 8 | class ExchangeRate(BaseModel, frozen=True): | ||
| 9 | is_valid: bool | ||
| 10 | is_crypto: bool | ||
| 11 | is_fiat: bool | ||
| 12 | source: CryptoAsset | FiatAsset | ||
| 13 | target: FiatAsset | ||
| 14 | rate: Decimal | ||
| 15 | |||
| 16 | |||
| 17 | __all__ = [ | ||
| 18 | "ExchangeRate", | ||
| 19 | ] | ||
diff --git a/src/async_crypto_pay_api/models/invoice.py b/src/async_crypto_pay_api/models/invoice.py new file mode 100644 index 0000000..e42dde0 --- /dev/null +++ b/src/async_crypto_pay_api/models/invoice.py | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | from datetime import datetime as Datetime | ||
| 2 | from decimal import Decimal | ||
| 3 | from enum import Enum | ||
| 4 | |||
| 5 | from pydantic import BaseModel, Field | ||
| 6 | |||
| 7 | from async_crypto_pay_api.models import CryptoAsset, FiatAsset, SwapAsset | ||
| 8 | |||
| 9 | |||
| 10 | class CurrencyType(Enum): | ||
| 11 | CRYPTO = "crypto" | ||
| 12 | FIAT = "fiat" | ||
| 13 | |||
| 14 | |||
| 15 | class InvoiceStatus(Enum): | ||
| 16 | ACTIVE = "active" | ||
| 17 | PAID = "paid" | ||
| 18 | EXPIRED = "expired" | ||
| 19 | |||
| 20 | |||
| 21 | class PaidButtonName(Enum): | ||
| 22 | VIEW_ITEM = "viewItem" | ||
| 23 | OPEN_CHANNEL = "openChannel" | ||
| 24 | OPEN_BOT = "openBot" | ||
| 25 | CALLBACK = "callback" | ||
| 26 | |||
| 27 | |||
| 28 | class Invoice(BaseModel, frozen=True): | ||
| 29 | invoice_id: int | ||
| 30 | hash: str | ||
| 31 | currency_type: CurrencyType | ||
| 32 | asset: CryptoAsset | None = None | ||
| 33 | fiat: FiatAsset | None = None | ||
| 34 | amount: Decimal | ||
| 35 | paid_asset: CryptoAsset | None = None | ||
| 36 | paid_amount: Decimal | None = None | ||
| 37 | paid_fiat_rate: Decimal | None = None | ||
| 38 | accepted_assets: list[CryptoAsset] | None = None | ||
| 39 | fee_asset: CryptoAsset | None = None | ||
| 40 | fee_amount: Decimal | None = None | ||
| 41 | # fee: Decimal | None = Field(deprecated=True) | ||
| 42 | pay_url: str | None = Field(default=None, deprecated=True) | ||
| 43 | bot_invoice_url: str | ||
| 44 | mini_app_invoice_url: str | ||
| 45 | web_app_invoice_url: str | ||
| 46 | description: str | None = None | ||
| 47 | status: InvoiceStatus | ||
| 48 | swap_to: SwapAsset | None = None | ||
| 49 | is_swapped: bool | None = None | ||
| 50 | swapped_uid: str | None = None | ||
| 51 | swapped_to: SwapAsset | None = None | ||
| 52 | swapped_rate: Decimal | None = None | ||
| 53 | swapped_output: Decimal | None = None | ||
| 54 | swapped_usd_amount: Decimal | None = None | ||
| 55 | swapped_usd_rate: Decimal | None = None | ||
| 56 | created_at: Datetime | ||
| 57 | paid_usd_rate: Decimal | None = None | ||
| 58 | # usd_rate: Decimal | None = Field(deprecated=True) | ||
| 59 | allow_comments: bool | ||
| 60 | allow_anonymous: bool | ||
| 61 | expiration_date: Datetime | None = None | ||
| 62 | paid_at: Datetime | None = None | ||
| 63 | paid_anonymously: bool | None = None | ||
| 64 | comment: str | None = None | ||
| 65 | hidden_message: str | None = None | ||
| 66 | payload: str | None = None | ||
| 67 | paid_btn_name: PaidButtonName | None = None | ||
| 68 | paid_btn_url: str | None = None | ||
| 69 | |||
| 70 | |||
| 71 | class InvoiceSearchStatus(Enum): | ||
| 72 | ACTIVE = "active" | ||
| 73 | PAID = "paid" | ||
| 74 | |||
| 75 | |||
| 76 | __all__ = [ | ||
| 77 | "CurrencyType", | ||
| 78 | "InvoiceStatus", | ||
| 79 | "PaidButtonName", | ||
| 80 | "Invoice", | ||
| 81 | "InvoiceSearchStatus", | ||
| 82 | ] | ||
diff --git a/src/async_crypto_pay_api/models/items.py b/src/async_crypto_pay_api/models/items.py new file mode 100644 index 0000000..05d60ea --- /dev/null +++ b/src/async_crypto_pay_api/models/items.py | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | from typing import Generic, TypeVar | ||
| 2 | |||
| 3 | from pydantic import BaseModel | ||
| 4 | |||
| 5 | T = TypeVar("T") | ||
| 6 | |||
| 7 | |||
| 8 | class Items(BaseModel, Generic[T], frozen=True): | ||
| 9 | items: list[T] | ||
| 10 | |||
| 11 | |||
| 12 | __all__ = [ | ||
| 13 | "Items", | ||
| 14 | ] | ||
diff --git a/src/async_crypto_pay_api/models/response.py b/src/async_crypto_pay_api/models/response.py new file mode 100644 index 0000000..6fcfa92 --- /dev/null +++ b/src/async_crypto_pay_api/models/response.py | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | from typing import Generic, TypeVar | ||
| 2 | |||
| 3 | from pydantic import BaseModel | ||
| 4 | |||
| 5 | R = TypeVar("R") | ||
| 6 | |||
| 7 | |||
| 8 | class Error(BaseModel, frozen=True): | ||
| 9 | code: int | ||
| 10 | name: str | ||
| 11 | |||
| 12 | |||
| 13 | class Response(BaseModel, Generic[R], frozen=True): | ||
| 14 | ok: bool | ||
| 15 | result: R | None = None | ||
| 16 | error: Error | None = None | ||
| 17 | |||
| 18 | |||
| 19 | __all__ = [ | ||
| 20 | "Error", | ||
| 21 | "Response", | ||
| 22 | ] | ||
diff --git a/src/async_crypto_pay_api/models/transfer.py b/src/async_crypto_pay_api/models/transfer.py new file mode 100644 index 0000000..fbc9ac3 --- /dev/null +++ b/src/async_crypto_pay_api/models/transfer.py | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | from datetime import datetime as Datetime | ||
| 2 | from decimal import Decimal | ||
| 3 | from typing import Literal | ||
| 4 | |||
| 5 | from pydantic import BaseModel | ||
| 6 | |||
| 7 | from async_crypto_pay_api.models import CryptoAsset | ||
| 8 | |||
| 9 | |||
| 10 | class Transfer(BaseModel, frozen=True): | ||
| 11 | transfer_id: int | ||
| 12 | spend_id: str | ||
| 13 | user_id: int | ||
| 14 | asset: CryptoAsset | ||
| 15 | amount: Decimal | ||
| 16 | status: Literal["completed"] | ||
| 17 | completed_at: Datetime | ||
| 18 | comment: str | None = None | ||
| 19 | |||
| 20 | |||
| 21 | __all__ = [ | ||
| 22 | "Transfer", | ||
| 23 | ] | ||
