Skip to content

Commit

Permalink
Develop (#15)
Browse files Browse the repository at this point in the history
* change version to 0.1.1dev (#5)

* Added:Error (#6)

* add APIException class

* add APIexception usage

* remove debugs

* handle no transaction found use case (#7)

* General scan (#8)

* Rename project to ScanWatch
change README to ScanWatch

* change client to accept BSCscan

* change ETHWatch to ScanWatch (#9)

* Typo fix (#10)

* change ETHWatch to ScanWatch

* fix args calls and comments

* Sql database (#11)

* add appdirs to the requirements and setup

* add utils

* add storage folder with DataBase and Table

* add utils and storage package to the setup

* add transaction tables

* add row tuple <-> dict conversion

* Add enums
Unite the getters for transactions tables

* add ScanDataBase

* Manager (#12)

* adapt the client to the NETWORK enum

* add tqdm to requirements and setup

* add ScanManager

* add a transactions getter to the Manager

* Docs (#13)

* add sphinx to the requirements

* fix sphinx duplicate target name and PEP8

* update README

* add sphinx docs files

* Bump to 0.1.1 (#14)

* add bug reports and feature request

* change version to 0.1.1

* add twine

* add links in the README
  • Loading branch information
EtWnn authored May 3, 2021
1 parent 6389076 commit 90bb7b4
Show file tree
Hide file tree
Showing 26 changed files with 1,209 additions and 50 deletions.
26 changes: 26 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: EtWnn

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1- Give your python version and the version of this library
2- Show the code you tried to execute
3- Show the full error / bug obtained

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Additional context**
Add any other context about the problem here.
20 changes: 20 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
2 changes: 0 additions & 2 deletions ETHWatch/__init__.py

This file was deleted.

99 changes: 80 additions & 19 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,40 +1,101 @@
========
ETHWatch
========
==============================
Welcome to ScanWatch 0.1.1
==============================

A local tracker of transactions for ETH address
It is a simple interface with the `etherscan <https://etherscan.io>`_ API.
Note
----

This library is under development by EtWnn, feel free to drop your suggestions or remarks in
the discussion tab of the git repo. You are also welcome to contribute by submitting PRs.

This library is made to retrieve price or candle history of crypto assets using multiple sources.

**Source Code:**
https://github.com/EtWnn/ScanWatch
**Documentation:**
https://scanwatch.readthedocs.io


This library is a local tracker of transactions for the Ethereum chain and the Binance Smart chain.
It is a simple interface with the `etherscan <https://etherscan.io>`_ and the
`bscscan <https://bscscan.com>`_ APIs and will save locally the results to gain time and avoid over-calling the APIs.

Quick Tour
----------

You will need to generate an API token to use this library.
Go on `etherscan <https://etherscan.io/myapikey>`__ for the Ethereum chain and on
`bscscan <https://bscscan.com/myapikey>`__ for the BSC chain.
(If you want to use both chains, you will need an API token for each).

``ScanWatch`` is not yet available on `PYPI <https://pypi.org/project/ScanWatch/>`_, install with ``pip``:

`Generate an API token <https://etherscan.io/myapikey>`_ in your etherscan account.
.. code:: bash
``ETHWatch`` is not yet available on ``PYPI``, but it can be installed with ``pip``:
pip install ScanWatch
You can also install the latest developments (not stable):

.. code:: bash
pip install git+https://github.com/EtWnn/ETHWatch.git
pip install git+https://github.com/EtWnn/ScanWatch.git@develop
You can then use your API token to instantiate the manager.

Example for Ethereum:

.. code:: python
from ScanWatch import ScanManager
from ScanWatch.utils.enums import NETWORK
Use your api token to initiate the manager:
api_token = "<ETH_API_TOKEN>"
address = "<YOUR_ETH_ADDRESS>"
manager = ScanManager(address, NETWORK.ETHER, api_token)
Example for BSC:

.. code:: python
from ETHWatch.Client import Client
from ScanWatch import ScanManager
from ScanWatch.utils.enums import NETWORK
api_token = "<BSC_API_TOKEN>"
address = "<YOUR_BSC_ADDRESS>"
manager = ScanManager(address, NETWORK.BSC, api_token)
Once the manager is setup, you can update the locally saved transactions:

.. code:: python
manager.update_all_transactions()
# all transactions updated for address 0xaAC...748E8: 100%|████████████| 4/4 [00:02<00:00, 1.86it/s]
This needs to be done only when new transactions have been made since the last time you called the update method.
Otherwise you can just fetch the transactions that have been previously saved, as shown below
(see the documentation for more details).

.. code:: python
from ScanWatch.utils.enums import TRANSACTION
manager.get_transactions(TRANSACTION.NORMAL) # normal transactions
api_token = "<API_TOKEN>"
manager.get_transactions(TRANSACTION.ERC20) # erc20 transactions
client = Client(api_token)
manager.get_transactions(TRANSACTION.ERC721) # erc721 transactions
eth_address = "<YOUR_ETH_ADDRESS>"
manager.get_transactions(TRANSACTION.INTERNAL) # internal transactions
# get the ETH balance
client.get_balance(eth_address)
# get your ETH transactions:
client.get_normal_transactions(eth_address)
Donation
--------

# get your ERC20 transactions:
client.get_erc20_transactions(eth_address)
If this library has helped you in any way, feel free to donate:

- **BTC**: 14ou4fMYoMVYbWEKnhADPJUNVytWQWx9HG
- **ETH**: 0xfb0ebcf8224ce561bfb06a56c3b9a43e1a4d1be2
- **LTC**: LfHgc969RFUjnmyLn41SRDvmT146jUg9tE
- **EGLD**: erd1qk98xm2hgztvmq6s4jwtk06g6laattewp6vh20z393drzy5zzfrq0gaefh
69 changes: 47 additions & 22 deletions ETHWatch/Client.py → ScanWatch/Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,30 @@

import requests

from ScanWatch.exceptions import APIException
from ScanWatch.utils.enums import NETWORK


class Client:
"""
Client for the etherscan.io API
Client for the etherscan.io API or the bscscan.io API
https://etherscan.io/apis
https://bscscan.com/apis
"""
BASE_URL = "https://api.etherscan.io/api"
BASE_ETH_URL = "https://api.etherscan.io/api"
BASE_BSC_URL = "https://api.bscscan.com/api"

def __init__(self, api_token: str, nt_type: NETWORK):
"""
def __init__(self, api_token: str):
:param api_token: token for the api
:type api_token: str
:param nt_type: type of the network
:type nt_type: NETWORK
"""
self.api_token = api_token
self.nt_type = nt_type

def get_mined_blocks(self, address: str, start_block: Optional[int] = None, end_block: Optional[int] = None):
"""
Expand All @@ -26,13 +40,16 @@ def get_mined_blocks(self, address: str, start_block: Optional[int] = None, end_
:return: List of mined blocks
:rtype: List[Dict]
"""
return self._get_transactions(address, 'getminedblocks', start_block, end_block)
try:
return self._get_transactions(address, 'getminedblocks', start_block, end_block)
except APIException:
return []

def get_erc721_transactions(self, address: str, start_block: Optional[int] = None, end_block: Optional[int] = None):
"""
fetch erc721 transactions on an eth address
fetch erc721 transactions on an eth / bsc address
:param address: ETH address
:param address: address
:type address: str
:param start_block: fetch transactions starting with this block
:type start_block: Optional[int]
Expand All @@ -45,9 +62,9 @@ def get_erc721_transactions(self, address: str, start_block: Optional[int] = Non

def get_erc20_transactions(self, address: str, start_block: Optional[int] = None, end_block: Optional[int] = None):
"""
fetch erc20 transactions on an eth address
fetch erc20 transactions on an eth / bsc address
:param address: ETH address
:param address: address
:type address: str
:param start_block: fetch transactions starting with this block
:type start_block: Optional[int]
Expand Down Expand Up @@ -85,9 +102,9 @@ def get_erc20_transactions(self, address: str, start_block: Optional[int] = None

def get_normal_transactions(self, address: str, start_block: Optional[int] = None, end_block: Optional[int] = None):
"""
fetch normal transactions on an eth address
fetch normal transactions on an eth / bsc address
:param address: ETH address
:param address: address
:type address: str
:param start_block: fetch transactions starting with this block
:type start_block: Optional[int]
Expand Down Expand Up @@ -125,9 +142,9 @@ def get_normal_transactions(self, address: str, start_block: Optional[int] = Non
def get_internal_transactions(self, address: str, start_block: Optional[int] = None,
end_block: Optional[int] = None):
"""
fetch internal transactions on an eth address
fetch internal transactions on an eth / bsc address
:param address: ETH address
:param address: address
:type address: str
:param start_block: fetch transactions starting with this block
:type start_block: Optional[int]
Expand All @@ -141,9 +158,9 @@ def get_internal_transactions(self, address: str, start_block: Optional[int] = N
def _get_transactions(self, address: str, action: str, start_block: Optional[int] = None,
end_block: Optional[int] = None):
"""
fetch transactions on an eth address
fetch transactions on an eth / bsc address
:param address: ETH address
:param address: address
:type address: str
:param action: name of the request for the api (ex 'txlist' or 'txlistinternal')
:type action:
Expand All @@ -162,8 +179,8 @@ def _get_transactions(self, address: str, action: str, start_block: Optional[int
action=action,
sort='asc',
address=address,
start_block=start_block,
end_block=end_block,
startblock=start_block,
endblock=end_block,
page=page_number,
offset=offset)
batch_txs = self.get_result(url)
Expand All @@ -176,9 +193,9 @@ def _get_transactions(self, address: str, action: str, start_block: Optional[int

def get_balance(self, address: str) -> float:
"""
fetch the current eth balance of an address
fetch the current eth / bnb balance of an address
:param address: ETH address
:param address: address
:type address: str
:return: ETH amount
:rtype: float
Expand All @@ -201,18 +218,26 @@ def get_url_request(self, **kwargs) -> str:
"""
_keywords = {**kwargs, "apikey": self.api_token}
string_kws = "&".join((f"{key}={value}" for key, value in _keywords.items()))
return f"{Client.BASE_URL}?{string_kws}"
if self.nt_type == NETWORK.ETHER:
base_url = Client.BASE_ETH_URL
elif self.nt_type == NETWORK.BSC:
base_url = Client.BASE_BSC_URL
else:
raise ValueError(f"unknown network type: {self.nt_type}")
return f"{base_url}?{string_kws}"

@staticmethod
def get_result(url: str):
"""
call the API with an url, raise if the status is not ok and return the API result
:param url: url to request for the etherscan.io
:param url: url to request for the etherscan.io or bscscan.com
:type url: str
:return: API result
:rtype: depend of the endpoint
"""
response = requests.get(url)
response.raise_for_status()
return response.json()['result']
r_json = response.json()
if int(r_json['status']) > 0 or r_json['message'] == 'No transactions found':
return r_json['result']
raise APIException(response)
Loading

0 comments on commit 90bb7b4

Please sign in to comment.