From 3896a8fe29d9607620b53f39293d50ccf772bfa0 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Tue, 28 Mar 2023 15:40:09 +0300 Subject: [PATCH] Support for CAT server Support get_transactions from https://ton.cat server --- pyTONPublicAPI/api.py | 64 ++++++++++++++++++++++++--------------- pyTONPublicAPI/servers.py | 15 +++++++++ pyTONPublicAPI/tests.py | 10 ++++-- pyTONPublicAPI/version.py | 2 +- 4 files changed, 64 insertions(+), 27 deletions(-) diff --git a/pyTONPublicAPI/api.py b/pyTONPublicAPI/api.py index 4ecccb2..8e069e2 100644 --- a/pyTONPublicAPI/api.py +++ b/pyTONPublicAPI/api.py @@ -1,4 +1,3 @@ -import requests from .servers import * @@ -48,7 +47,7 @@ def __request(self, method, use_address = True, **kwargs): self.api_server.add_parameters(data) try: - resp = requests.get(url=self.api_server.api_url + method, headers=headers, params=data, timeout=self.timeout).json() + resp = self.api_server.request_get(method=method, headers=headers, params=data, timeout=self.timeout) except ValueError as e: message = "Response decode failed: {}".format(e) if self.print_errors: @@ -71,7 +70,9 @@ def __request(self, method, use_address = True, **kwargs): print(message) raise pyTONException(-99, message) - if self.__is_tonapi_server(): + if isinstance(resp, list): + return resp + elif self.__is_tonapi_server(): if not resp.get("message"): return resp else: @@ -85,6 +86,13 @@ def __request(self, method, use_address = True, **kwargs): if isinstance(code, str) and code.isdigit(): code = int(code) raise pyTONException(code, "Error code returned") + elif ("statusCode" in resp): + if self.print_errors: + print("Response: {}".format(resp)) + code = resp.get("statusCode") + if isinstance(code, str) and code.isdigit(): + code = int(code) + raise pyTONException(code, "Error code returned") elif ("code" in resp) or ("message" in resp): if self.print_errors: print("Response: {}".format(resp)) @@ -118,7 +126,7 @@ def get_address_information(self, address = None): return self.__request(method, address = address).get("result") # noinspection PyShadowingBuiltins - def get_transactions(self, address = None, limit = None, lt = None, hash = None, to_lt = None, archival = None): + def get_transactions(self, address = None, limit = None, lt = None, hash = None, to_lt = None, archival = None, offset = None): """ getTransactions Use this method to get balance (in nanotons) and state of a given address. @@ -128,6 +136,7 @@ def get_transactions(self, address = None, limit = None, lt = None, hash = None, :param hash: (Optional) Hash of transaction to start with, must be sent with lt :param to_lt: (Optional, not all servers supports) Logical time of transaction to finish with (to get tx from lt to to_lt). :param archival: (Optional, not all servers supports) By default getTransaction request is processed by any available liteserver. If archival=true only liteservers with full history are used. + :param offset: (Optional, not all servers supports) Offset of transaction to start with :return: """ params = {} @@ -138,6 +147,11 @@ def get_transactions(self, address = None, limit = None, lt = None, hash = None, params["minLt"] = lt if to_lt is not None: params["maxLt"] = to_lt + elif isinstance(self.api_server, pyTONAPIServerCAT): + method = "address/%address%/transactions" + return_name = "" + if offset is not None: + params["offset"] = offset else: method = "getTransactions" return_name = "result" @@ -151,10 +165,12 @@ def get_transactions(self, address = None, limit = None, lt = None, hash = None, params["hash"] = hash if archival is not None: params["archival"] = archival - if params: - return self.__request(method, address = address, **params).get(return_name) + if offset is not None: + params["offset"] = offset + if return_name: + return self.__request(method, address=address, **params).get(return_name) else: - return self.__request(method, address = address).get(return_name) + return self.__request(method, address = address, **params) def get_address_balance(self, address = None): """ @@ -211,7 +227,9 @@ def get_block_information(self, seqno, workchain_id = None): :return: Identifier in human-readable format """ method = "getBlockInformation" - params = {"seqno": seqno} + params = { + "seqno": seqno + } if workchain_id is not None: params["workchain_id"] = workchain_id return self.__request(method, use_address = False, **params).get("result") @@ -304,8 +322,7 @@ def lookup_block(self, workchain, shard, seqno = None, lt = None, unixtime = Non params["lt"] = lt if unixtime is not None: params["unixtime"] = unixtime - if params: - return self.__request(method, **params).get("result") + return self.__request(method, **params).get("result") def shards(self, seqno): """ @@ -318,8 +335,7 @@ def shards(self, seqno): params = { "seqno": seqno, } - if params: - return self.__request(method, **params).get("result") + return self.__request(method, **params).get("result") def get_block_transactions(self, workchain, shard, seqno, root_hash = None, file_hash = None, after_lt = None, after_hash = None, count = None): """ @@ -351,8 +367,7 @@ def get_block_transactions(self, workchain, shard, seqno, root_hash = None, file params["after_hash"] = after_hash if count is not None: params["count"] = count - if params: - return self.__request(method, **params).get("result") + return self.__request(method, **params).get("result") def get_block_header(self, workchain, shard, seqno, root_hash = None, file_hash = None): """ @@ -375,8 +390,7 @@ def get_block_header(self, workchain, shard, seqno, root_hash = None, file_hash params["root_hash"] = root_hash if file_hash is not None: params["file_hash"] = file_hash - if params: - return self.__request(method, **params).get("result") + return self.__request(method, **params).get("result") def try_locate_tx(self, source, destination, created_lt): """ @@ -393,8 +407,7 @@ def try_locate_tx(self, source, destination, created_lt): "destination": destination, "created_lt": created_lt, } - if params: - return self.__request(method, **params).get("result") + return self.__request(method, **params).get("result") def try_locate_result_tx(self, source, destination, created_lt): """ @@ -411,8 +424,7 @@ def try_locate_result_tx(self, source, destination, created_lt): "destination": destination, "created_lt": created_lt, } - if params: - return self.__request(method, **params).get("result") + return self.__request(method, **params).get("result") def try_locate_source_tx(self, source, destination, created_lt): """ @@ -429,8 +441,7 @@ def try_locate_source_tx(self, source, destination, created_lt): "destination": destination, "created_lt": created_lt, } - if params: - return self.__request(method, **params).get("result") + return self.__request(method, **params).get("result") def account_get_info(self, address = None): """ @@ -462,11 +473,16 @@ def jetton_get_history(self, address = None, jetton_master = None, limit = 100): Get all Jetton transfers for account :param address: address in raw (hex without 0x) or base64url format :param jetton_master: (Optional) Jetton master address - :param limit: (Optional) Limit of transactions + :param limit: Limit of transactions (default = 100) :return: """ method = "jetton/getHistory" - return self.__request(method, address = address, jetton_master = jetton_master, limit = limit).get("events") + params = { + "limit": limit, + } + if jetton_master: + params["jetton_master"] = jetton_master + return self.__request(method, address = address, **params).get("events") def jetton_get_info(self, address = None): """ diff --git a/pyTONPublicAPI/servers.py b/pyTONPublicAPI/servers.py index 9e8b896..4dc3add 100644 --- a/pyTONPublicAPI/servers.py +++ b/pyTONPublicAPI/servers.py @@ -1,3 +1,4 @@ +import requests from enum import Enum from abc import ABC @@ -25,6 +26,9 @@ def add_parameters(self, params): params[dest_name] = params[source_name] del params[source_name] + def request_get(self, method = None, headers=None, params=None, timeout=None): + return requests.get(url=self.api_url + method, headers=headers, params=params, timeout=timeout).json() + # noinspection PyPep8Naming class pyTONAPIServerTonSh(pyTONAPIServer): @@ -74,3 +78,14 @@ class pyTONAPIServerTonAPITest(pyTONAPIServerTonAPI): def __init__(self, api_key = None): super().__init__(api_key = api_key) self.api_url = "https://testnet.tonapi.io/v1/" + + +# noinspection PyPep8Naming +class pyTONAPIServerCAT(pyTONAPIServer): + def __init__(self): + super().__init__(pyTONAPIServerTypes.TonCenter, "https://api.ton.cat/v2/contracts/") + + def request_get(self, method = None, headers=None, params=None, timeout=None): + method = method.replace("%address%", params["address"]) + params.pop("address") + return requests.get(url=self.api_url + method, headers=headers, params=params, timeout=timeout).json() diff --git a/pyTONPublicAPI/tests.py b/pyTONPublicAPI/tests.py index 5cab0f2..340722c 100644 --- a/pyTONPublicAPI/tests.py +++ b/pyTONPublicAPI/tests.py @@ -1,10 +1,10 @@ import inspect from time import sleep try: - from pyTONPublicAPI import pyTONPublicAPI, pyTONException, pyTONAPIServerTonSh, pyTONAPIServerTonCenter, pyTONAPIServerTonAPI + from pyTONPublicAPI import pyTONPublicAPI, pyTONException, pyTONAPIServerTonSh, pyTONAPIServerTonCenter, pyTONAPIServerTonAPI, pyTONAPIServerCAT except: from api import pyTONPublicAPI, pyTONException - from servers import pyTONAPIServerTonSh, pyTONAPIServerTonCenter, pyTONAPIServerTonAPI + from servers import pyTONAPIServerTonSh, pyTONAPIServerTonCenter, pyTONAPIServerTonAPI, pyTONAPIServerCAT ton_address = "EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N" @@ -71,6 +71,11 @@ def test_tonapi_functions(): run_and_print(lambda: client.jetton_get_history(address=ton_address, limit=10)) run_and_print(lambda: client.jetton_get_info(address="EQCt1ZIrhvcZn2iw4DMrkHhSmlJNpC063ykc2fIzzmLBuZ14")) +def test_cat_functions(): + client = pyTONPublicAPI(print_errors=True, api_server=pyTONAPIServerCAT()) + run_and_print(lambda: client.get_transactions(address=ton_address)) + run_and_print(lambda: client.get_transactions(address=ton_address, limit=1)) + test_no_address(api_server=pyTONAPIServerTonSh()) test_with_address(api_server=pyTONAPIServerTonSh()) @@ -83,3 +88,4 @@ def test_tonapi_functions(): test_tonsh_functions() test_toncenter_functions() test_tonapi_functions() +test_cat_functions() diff --git a/pyTONPublicAPI/version.py b/pyTONPublicAPI/version.py index 631c357..86e1c3b 100644 --- a/pyTONPublicAPI/version.py +++ b/pyTONPublicAPI/version.py @@ -1,3 +1,3 @@ # Versions should comply with PEP440. # This line is parsed in setup.py: -__version__ = '0.1.1' +__version__ = '0.2.0'