cryptocloud-sdk 0.1.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ from .merchant import CryptoCloud
2
+
3
+ __all__ = [
4
+ "CryptoCloud",
5
+ ]
@@ -0,0 +1,25 @@
1
+ from .balance import CoinBalance
2
+ from .currency import InvoiceCurrency, BalanceCurrency, SupportedCryptoCurrency, SupportedFiatCurrency
3
+ from .invoice import TimeToPay, AddedInvoiceParamsInput, InvoiceInput, CreatedInvoice, InvoiceInfo
4
+ from .network import CurrencyNetwork
5
+ from .postback import InvoicePostback
6
+ from .project import Project
7
+ from .static_wallet import StaticWallet
8
+ from .stats import Stats
9
+
10
+ __all__ = [
11
+ "InvoiceCurrency",
12
+ "BalanceCurrency",
13
+ "SupportedCryptoCurrency",
14
+ "SupportedFiatCurrency",
15
+ "TimeToPay",
16
+ "AddedInvoiceParamsInput",
17
+ "InvoiceInput",
18
+ "CreatedInvoice",
19
+ "InvoiceInfo",
20
+ "Project",
21
+ "CoinBalance",
22
+ "StaticWallet",
23
+ "InvoicePostback",
24
+ "Stats"
25
+ ]
@@ -0,0 +1,11 @@
1
+ from pydantic import BaseModel, confloat
2
+
3
+ from .currency import BalanceCurrency
4
+
5
+
6
+ class CoinBalance(BaseModel):
7
+ currency: BalanceCurrency
8
+ balance_crypto: confloat(ge=0)
9
+ balance_usd: confloat(ge=0)
10
+ available_balance: confloat(ge=0)
11
+ available_balance_usd: confloat(ge=0)
@@ -0,0 +1,82 @@
1
+ from dataclasses import dataclass
2
+
3
+ from pydantic import BaseModel, conint
4
+
5
+ from .network import CurrencyNetwork
6
+
7
+
8
+ @dataclass(slots=True, frozen=True)
9
+ class SupportedCryptoCurrency:
10
+ """ Supported Crypto Currencies
11
+ https://docs.cryptocloud.plus/ru/api-reference-v2/create-invoice#opisanie-dopolnitelnykh-parametrov
12
+ """
13
+ USDT_TRC20 = "USDT_TRC20"
14
+ USDC_TRC20 = "USDC_TRC20"
15
+ TUSD_TRC20 = "TUSD_TRC20"
16
+ USDT_ERC20 = "USDT_ERC20"
17
+ USDC_ERC20 = "USDC_ERC20"
18
+ TUSD_ERC20 = "TUSD_ERC20"
19
+ USDD_TRC20 = "USDD_TRC20"
20
+ SHIB_ERC20 = "SHIB_ERC20"
21
+ USDT_BSC = "USDT_BSC"
22
+ USDC_BSC = "USDC_BSC"
23
+ TUSD_BSC = "TUSD_BSC"
24
+ USDT_TON = "USDT_TON"
25
+ BTC = "BTC"
26
+ LTC = "LTC"
27
+ ETH = "ETH"
28
+ TRX = "TRX"
29
+ BNB = "BNB"
30
+ TON = "TON"
31
+
32
+
33
+ @dataclass(slots=True, frozen=True)
34
+ class SupportedFiatCurrency:
35
+ USD = "USD"
36
+ UZS = "UZS"
37
+ KGS = "KGS"
38
+ KZT = "KZT"
39
+ AMD = "AMD"
40
+ AZN = "AZN"
41
+ BYN = "BYN"
42
+ AUD = "AUD"
43
+ TRY = "TRY"
44
+ AED = "AED"
45
+ CAD = "CAD"
46
+ CNY = "CNY"
47
+ HKD = "HKD"
48
+ IDR = "IDR"
49
+ INR = "INR"
50
+ JPY = "JPY"
51
+ PHP = "PHP"
52
+ SGD = "SGD"
53
+ THB = "THB"
54
+ VND = "VND"
55
+ MYR = "MYR"
56
+ RUB = "RUB"
57
+ UAH = "UAH"
58
+ EUR = "EUR"
59
+ GBP = "GBP"
60
+
61
+
62
+ class _BaseCurrency(BaseModel):
63
+ id: conint(ge=0)
64
+ code: str
65
+ name: str
66
+ is_email_required: bool
67
+ stablecoin: bool
68
+ icon_base: str
69
+ icon_network: str
70
+ icon_qr: str
71
+ order: conint(ge=0)
72
+
73
+
74
+ class InvoiceCurrency(_BaseCurrency):
75
+ network: CurrencyNetwork
76
+ fullcode: str
77
+
78
+
79
+ class BalanceCurrency(_BaseCurrency):
80
+ enable: bool | None = None
81
+ obj_network: CurrencyNetwork
82
+ short_code: str
@@ -0,0 +1,63 @@
1
+ from datetime import datetime
2
+ from typing import Literal
3
+
4
+ from pydantic import BaseModel, confloat
5
+
6
+ from .currency import InvoiceCurrency
7
+ from .project import Project
8
+
9
+
10
+ class _BasePostInvoice(BaseModel):
11
+ uuid: str
12
+ expiry_date: datetime
13
+ address: str
14
+ side_commission: str
15
+ amount: confloat(gt=0)
16
+ amount_usd: confloat(gt=0)
17
+ fee: confloat(gt=0)
18
+ fee_usd: confloat(gt=0)
19
+ service_fee: confloat(gt=0)
20
+ service_fee_usd: confloat(gt=0)
21
+ status: str
22
+ currency: InvoiceCurrency
23
+ project: Project
24
+ test_mode: bool
25
+
26
+
27
+ class TimeToPay(BaseModel):
28
+ minutes: int | None = 00
29
+ hours: int | None = 2
30
+
31
+
32
+ class AddedInvoiceParamsInput(BaseModel):
33
+ time_to_pay: TimeToPay | None = None
34
+ email_to_send: str | None = None
35
+ available_currencies: list[str] | None = None
36
+ cryptocurrency: str | None = None
37
+ period: Literal["month", "week", "day"] | None = None
38
+
39
+
40
+ class InvoiceInput(BaseModel):
41
+ amount: confloat(gt=0)
42
+
43
+ currency: str | None = "USD"
44
+ order_id: str | None = None
45
+ email: str | None = None
46
+
47
+ add_fields: AddedInvoiceParamsInput | None = None
48
+
49
+
50
+ class CreatedInvoice(_BasePostInvoice):
51
+ created: datetime
52
+ amount_in_fiat: confloat(gt=0)
53
+ fiat_currency: str
54
+ side_commission_service: str
55
+ is_email_required: bool
56
+ link: str
57
+
58
+
59
+ class InvoiceInfo(_BasePostInvoice):
60
+ received: confloat(ge=0)
61
+ received_usd: confloat(ge=0)
62
+ order_id: str | None = None
63
+ side_commission_cc: str
@@ -0,0 +1,8 @@
1
+ from pydantic import BaseModel, conint
2
+
3
+
4
+ class CurrencyNetwork(BaseModel):
5
+ code: str
6
+ id: conint(ge=0)
7
+ icon: str
8
+ fullname: str
@@ -0,0 +1,15 @@
1
+ from typing import Literal
2
+
3
+ from pydantic import BaseModel, constr, confloat
4
+
5
+
6
+ class InvoicePostback(BaseModel):
7
+ """ Invoice postback
8
+ https://docs.cryptocloud.plus/ru/api-reference-v2/postback
9
+ """
10
+ status: Literal["success"]
11
+ invoice_id: constr(max_length=12)
12
+ amount_crypto: confloat(ge=0)
13
+ currency: constr(max_length=12)
14
+ amount_usdt: confloat(ge=0)
15
+ order_id: int | None = None
@@ -0,0 +1,9 @@
1
+ from pydantic import BaseModel, conint
2
+
3
+
4
+ class Project(BaseModel):
5
+ id: conint(ge=0)
6
+ name: str
7
+ fail: str
8
+ success: str
9
+ logo: str | None = None
@@ -0,0 +1,9 @@
1
+ from pydantic import BaseModel
2
+
3
+ from .currency import BalanceCurrency
4
+
5
+
6
+ class StaticWallet(BaseModel):
7
+ uuid: str
8
+ address: str
9
+ currency: BalanceCurrency
@@ -0,0 +1,24 @@
1
+ from pydantic import BaseModel, conint, confloat
2
+
3
+
4
+ class StatsCount(BaseModel):
5
+ all: conint(ge=0)
6
+ created: conint(ge=0)
7
+ paid: conint(ge=0)
8
+ overpaid: conint(ge=0)
9
+ partial: conint(ge=0)
10
+ canceled: conint(ge=0)
11
+
12
+
13
+ class StatsAmount(BaseModel):
14
+ all: confloat(ge=0)
15
+ created: confloat(ge=0)
16
+ paid: confloat(ge=0)
17
+ overpaid: confloat(ge=0)
18
+ partial: confloat(ge=0)
19
+ canceled: confloat(ge=0)
20
+
21
+
22
+ class Stats(BaseModel):
23
+ count: StatsCount
24
+ amount: StatsAmount
@@ -0,0 +1,10 @@
1
+ class BadRequestError(Exception):
2
+ ...
3
+
4
+
5
+ class UnauthorizedError(Exception):
6
+ ...
7
+
8
+
9
+ class ForbiddenError(Exception):
10
+ ...
@@ -0,0 +1,60 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Literal
3
+
4
+ import aiohttp
5
+
6
+ from .errors import BadRequestError, UnauthorizedError, ForbiddenError
7
+
8
+
9
+ class BaseHttpExecutor(ABC):
10
+ def __init__(
11
+ self,
12
+ headers: dict
13
+ ):
14
+ self.__headers = headers
15
+
16
+ async def make_request(
17
+ self,
18
+ url: str,
19
+ method: Literal["get", "post"] = "post",
20
+ load_response_body: bool = True,
21
+ **kwargs
22
+ ) -> (aiohttp.ClientResponse, dict):
23
+ async with aiohttp.ClientSession() as session:
24
+ async with getattr(session, method)(
25
+ url=url,
26
+ headers=self.__headers,
27
+ **kwargs
28
+ ) as resp:
29
+ if resp.status == 404:
30
+ raise BadRequestError(f"The requested {url=} not found. Check API updates.")
31
+
32
+ resp_body = await resp.json()
33
+
34
+ self._check_response_status(resp, resp_body)
35
+
36
+ return resp, resp_body if load_response_body else {}
37
+
38
+ @abstractmethod
39
+ def _check_response_status(self, response: aiohttp.ClientResponse, response_body: dict) -> None:
40
+ raise NotImplementedError
41
+
42
+
43
+ class CryptoCloudHttpExecutor(BaseHttpExecutor):
44
+ def _check_response_status(self, response: aiohttp.ClientResponse, response_body: dict) -> None:
45
+ resp_code = response.status
46
+
47
+ match resp_code:
48
+ case 400:
49
+ raise BadRequestError(self._format_error(resp_code, response_body.get("result")))
50
+ case 401:
51
+ raise UnauthorizedError(self._format_error(resp_code, response_body.get("detail")))
52
+ case 403:
53
+ raise ForbiddenError(self._format_error(resp_code, response_body.get("detail")))
54
+
55
+ @staticmethod
56
+ def _format_error(code: int, tip: str) -> str:
57
+ text = f"Returned [{code}] error because - '{tip}'. " \
58
+ "Make sure that creds and params was correctly passed."
59
+
60
+ return text
@@ -0,0 +1,114 @@
1
+ from datetime import date
2
+
3
+ from . import dto
4
+ from .http_executor import CryptoCloudHttpExecutor
5
+
6
+
7
+ class CryptoCloud:
8
+ def __init__(
9
+ self,
10
+ api_token: str,
11
+ shop_id: str,
12
+ host="https://api.cryptocloud.plus",
13
+ version: str = "/v2"
14
+ ):
15
+ self._http = CryptoCloudHttpExecutor(
16
+ headers={
17
+ "Content-Type": "application/json",
18
+ "Authorization": f"Token {api_token}"
19
+ }
20
+ )
21
+ self._base_url = f"{host}{version}"
22
+ self._shop_id = shop_id
23
+
24
+ async def create_invoice(self, invoice: dto.InvoiceInput) -> dto.CreatedInvoice:
25
+ """
26
+ https://docs.cryptocloud.plus/ru/api-reference-v2/create-invoice#request-body
27
+ """
28
+ url = self._base_url + "/invoice/create"
29
+ payload = invoice.model_dump(exclude_none=True) | {"shop_id": self._shop_id}
30
+
31
+ _, body = await self._http.make_request(
32
+ url=url,
33
+ json=payload,
34
+ )
35
+
36
+ return dto.CreatedInvoice(**body.get("result"))
37
+
38
+ async def get_invoices(self, uuids: list[str]) -> list[dto.InvoiceInfo]:
39
+ """
40
+ https://docs.cryptocloud.plus/ru/api-reference-v2/invoice-list#request-body
41
+ """
42
+ url = self._base_url + "/invoice/merchant/info"
43
+
44
+ _, body = await self._http.make_request(
45
+ url=url,
46
+ json={"uuids": uuids},
47
+ )
48
+
49
+ return [dto.InvoiceInfo(**i) for i in body.get("result")]
50
+
51
+ async def cancel_invoice(self, uuid: str) -> None:
52
+ """ https://docs.cryptocloud.plus/ru/api-reference-v2/cancel-invoice#request-body
53
+
54
+ Request will be executed successfully only when invoice has 'created' status
55
+ :return None -> if canceled without any problem
56
+ :return Exception -> when some param is not correct """
57
+
58
+ url = self._base_url + "/invoice/merchant/canceled"
59
+
60
+ _, body = await self._http.make_request(
61
+ url=url,
62
+ json={"uuid": uuid},
63
+ )
64
+
65
+ async def get_balance(
66
+ self, in_currency: dto.SupportedCryptoCurrency | None = None
67
+ ) -> list[dto.CoinBalance] | dto.CoinBalance:
68
+ """
69
+ https://docs.cryptocloud.plus/ru/api-reference-v2/balance#poluchit-balans
70
+ """
71
+ url = self._base_url + "/merchant/wallet/balance/all"
72
+
73
+ _, body = await self._http.make_request(url=url)
74
+
75
+ if in_currency:
76
+ in_curr = [b for b in body.get("result") if b.get("currency").get("code") == in_currency]
77
+ if in_curr:
78
+ return dto.CoinBalance(**in_curr.pop())
79
+
80
+ return [dto.CoinBalance(**i) for i in body.get("result")]
81
+
82
+ async def get_stats(self, start: date, end: date) -> dto.Stats:
83
+ """
84
+ https://docs.cryptocloud.plus/ru/api-reference-v2/statistics#request-body
85
+ """
86
+ url = self._base_url + "/invoice/merchant/statistics"
87
+ payload = {
88
+ "start": start.strftime("%d.%m.%Y"),
89
+ "end": end.strftime("%d.%m.%Y")
90
+ }
91
+
92
+ _, body = await self._http.make_request(
93
+ url=url,
94
+ json=payload,
95
+ )
96
+
97
+ return dto.Stats(**body.get("result"))
98
+
99
+ async def create_static_wallet(self, currency: str, identify: str) -> dto.StaticWallet:
100
+ """
101
+ https://docs.cryptocloud.plus/ru/api-reference-v2/static-wallet#request-body
102
+ """
103
+ url = self._base_url + "/invoice/static/create"
104
+
105
+ _, body = await self._http.make_request(
106
+ url=url,
107
+ json={
108
+ "shop_id": self._shop_id,
109
+ "currency": currency,
110
+ "identify": identify,
111
+ },
112
+ )
113
+
114
+ return dto.StaticWallet(**body.get("result"))
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.3
2
+ Name: cryptocloud-sdk
3
+ Version: 0.1.0
4
+ Summary:
5
+ Keywords: async,crypto cloud,python,sdk
6
+ Author: Никита Прожога
7
+ Author-email: fofmow@gmail.com
8
+ Requires-Python: >=3.10
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Dist: aiohttp (>=3.11.11,<4.0.0)
13
+ Requires-Dist: pydantic (>=2.10.5,<3.0.0)
14
+ Project-URL: Homepage, https://github.com/fofmow/crypto-cloud-sdk
15
+ Project-URL: Repository, https://github.com/fofmow/crypto-cloud-sdk
16
+ Description-Content-Type: text/markdown
17
+
18
+ # Crypto Cloud SDK — простая асинхронная библиотека для работы с API [CryptoCloud](https://cryptocloud.plus/)
19
+
20
+ ### 💡 Регистрация мерчанта и получение API ключей [описаны в документации](https://docs.cryptocloud.plus/ru/start/get-api-keys)
21
+
22
+ ## Примеры использования / Use cases
23
+
24
+ ```python
25
+ import asyncio
26
+ from datetime import date, timedelta
27
+
28
+ from cryptocloud_sdk import CryptoCloud, dto, errors
29
+
30
+
31
+ async def main():
32
+ merchant = CryptoCloud(
33
+ api_token="YOUR_API_TOKEN",
34
+ shop_id="YOUR_SHOP_ID"
35
+ )
36
+
37
+ invoice: dto.CreatedInvoice = await merchant.create_invoice(
38
+ invoice=dto.InvoiceInput(
39
+ amount=250,
40
+ currency="USD" # or dto.currency.SupportedFiatCurrency.USD
41
+ )
42
+ )
43
+ print(f"Invoice url is {invoice.link}")
44
+
45
+ invoices: list[dto.InvoiceInfo] = await merchant.get_invoices(uuids=[invoice.uuid])
46
+
47
+ canceled = await merchant.cancel_invoice(invoice.uuid)
48
+
49
+ balances: list[dto.CoinBalance] = await merchant.get_balance()
50
+
51
+ statictics: dto.Stats = await merchant.get_stats(
52
+ start=date.today() - timedelta(days=3),
53
+ end=date.today()
54
+ )
55
+
56
+ static_wallet: dto.StaticWallet = await merchant.create_static_wallet(
57
+ currency="BTC", # or dto.currency.SupportedCryptoCurrency.BTC ,
58
+ identify="my-new-user-7"
59
+ )
60
+
61
+ # Handling errors
62
+ try:
63
+ await merchant.get_balance()
64
+ except errors.UnauthorizedError:
65
+ ... # your code
66
+ except errors.ForbiddenError:
67
+ ... # your code
68
+ except errors.BadRequestError:
69
+ ... # your code
70
+
71
+
72
+ if __name__ == "__main__":
73
+ asyncio.run(main())
74
+ ```
75
+
76
+ ####
77
+
78
+ ## [Want to donate? Look at real app used CryptoCloud 😎](https://t.me/todonators_bot)
79
+
80
+ ##
81
+
82
+
83
+
@@ -0,0 +1,16 @@
1
+ cryptocloud_sdk/__init__.py,sha256=n0aN5xtKtjxsB6UiPZqlPwiA-RfR3emgKgx0fJAeSP8,68
2
+ cryptocloud_sdk/dto/__init__.py,sha256=JEh8-t3d-545xqEf5WRkvQr-uu53fibHViisx06n45U,723
3
+ cryptocloud_sdk/dto/balance.py,sha256=QJTdXVSgHf5nsEYj1n_GoqS6_OIHzAvzbeGDApbJECQ,289
4
+ cryptocloud_sdk/dto/currency.py,sha256=H8xYKRthaXxvEdTBYWEZys4TFt-o_aG5Gs3yZbT-mMk,1661
5
+ cryptocloud_sdk/dto/invoice.py,sha256=RSSM837x2TBTEsVFrnH8gqL6ZAStTVGa_fNbXnQX5qs,1480
6
+ cryptocloud_sdk/dto/network.py,sha256=M4QylRtR_mIguNw9r80LGeCyciu2PH3QXq6_2sxdaC0,142
7
+ cryptocloud_sdk/dto/postback.py,sha256=dAtU_1GEZRce8ggwPAqquQlTkovoPwMIHptOW0T-zEo,412
8
+ cryptocloud_sdk/dto/project.py,sha256=vbpHZV6zHwknU_oSKNAfC6CWuiBlMrJvNXh7XUg4xK4,161
9
+ cryptocloud_sdk/dto/static_wallet.py,sha256=MtI5IiN9oVwXlm9T7VT-yH5HP553vZzZ_IcSED99q1A,164
10
+ cryptocloud_sdk/dto/stats.py,sha256=4g6qIxWcqJHTQ0ugmDD7AT7GG0Pq6Jsp6ZO-kC6T7Gk,498
11
+ cryptocloud_sdk/errors.py,sha256=zi9zNqHrBaapyU9jKegen2j9CnSDXmkvTVv5Z04mzkE,131
12
+ cryptocloud_sdk/http_executor.py,sha256=V1WYIIYPZEbznfjk_lQjjqQT9M6kRH1Fq8af7b0YO14,2050
13
+ cryptocloud_sdk/merchant.py,sha256=n0ykTR_eBYAwitfjl4X1D4OjmD0Gam7L0cHjpHEsrfU,3840
14
+ cryptocloud_sdk-0.1.0.dist-info/METADATA,sha256=jx5hhjNVEFF16dYa8tutrPS2M0r1VTh9kky61m4FveI,2475
15
+ cryptocloud_sdk-0.1.0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
16
+ cryptocloud_sdk-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.0.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any