Skip to content

Commit

Permalink
Merge pull request #22 from EtWnn/develop
Browse files Browse the repository at this point in the history
to version 0.1.2
  • Loading branch information
EtWnn authored Dec 27, 2021
2 parents 97f60cd + cc847eb commit 28f1b44
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 28 deletions.
16 changes: 15 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
==============================
Welcome to ScanWatch 0.1.1
Welcome to ScanWatch 0.1.2
==============================

Note
Expand Down Expand Up @@ -88,6 +88,20 @@ Otherwise you can just fetch the transactions that have been previously saved, a
manager.get_transactions(TRANSACTION.INTERNAL) # internal transactions
Main / test nets
----------------

If you want to switch from main to test nets, you can specify the net name at the manager creation:

.. code:: python
manager = ScanManager(address, <network>, api_token, <net_name>)
Supported nets are:
- For Ethereum: "main", "goerli", "kovan", "rinkeby", "ropsten"
- For BSC: "main", "test"


Donation
--------

Expand Down
40 changes: 27 additions & 13 deletions ScanWatch/Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,41 @@ class Client:
https://etherscan.io/apis
https://bscscan.com/apis
"""
BASE_ETH_URL = "https://api.etherscan.io/api"
BASE_BSC_URL = "https://api.bscscan.com/api"
BASE_URLS = {
NETWORK.BSC: {
"main": "https://api.bscscan.com/api",
"test": "https://api-testnet.bscscan.com/api"
},
NETWORK.ETHER: {
"main": "https://api.etherscan.io/api",
"goerli": "https://api-goerli.etherscan.io/api",
"kovan": "https://api-kovan.etherscan.io/api",
"rinkeby": "https://api-rinkeby.etherscan.io/api",
"ropsten": "https://api-ropsten.etherscan.io/api"
}
}

def __init__(self, api_token: str, nt_type: NETWORK):
def __init__(self, api_token: str, nt_type: NETWORK, net: str = "main"):
"""
:param api_token: token for the api
:type api_token: str
:param nt_type: type of the network
:type nt_type: NETWORK
:param net: name of the network, used to differentiate main and test nets
:type net: str, default 'main'
"""
self.api_token = api_token
self.nt_type = nt_type
self.net = net
self.get_url_request() # test if network parameters are valid

def get_mined_blocks(self, address: str, start_block: Optional[int] = None, end_block: Optional[int] = None):
"""
fetch mined blocks by an eth address
fetch mined blocks by an address
:param address: ETH address
:param address: network address
:type address: str
:param start_block: fetch mined blocks starting with this block
:type start_block: Optional[int]
Expand Down Expand Up @@ -209,7 +224,7 @@ def get_balance(self, address: str) -> float:

def get_url_request(self, **kwargs) -> str:
"""
Construct the url to make a request to the etherscan.io API
Construct the url to make a request to the etherscan.io / bscscan.com API
:param kwargs: keywords args for the endpoint
:type kwargs: Any
Expand All @@ -218,12 +233,10 @@ 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()))
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}")
try:
base_url = self.BASE_URLS[self.nt_type][self.net]
except KeyError as err:
raise ValueError(f"unknown network with type {self.nt_type} and name {self.net}") from err
return f"{base_url}?{string_kws}"

@staticmethod
Expand All @@ -236,7 +249,8 @@ def get_result(url: str):
:return: API result
:rtype: depend of the endpoint
"""
response = requests.get(url)
response = requests.get(url, headers={"User-Agent": "Mozilla/5.0"})
response.raise_for_status()
r_json = response.json()
if int(r_json['status']) > 0 or r_json['message'] == 'No transactions found':
return r_json['result']
Expand Down
13 changes: 8 additions & 5 deletions ScanWatch/ScanManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class ScanManager:
This class is the interface between the user, the API and the Database
"""

def __init__(self, address: str, nt_type: NETWORK, api_token: str):
def __init__(self, address: str, nt_type: NETWORK, api_token: str, net: str = "main"):
"""
Initiate the manager
Expand All @@ -20,10 +20,13 @@ def __init__(self, address: str, nt_type: NETWORK, api_token: str):
:type nt_type: NETWORK
:param api_token: token to communicate with the API
:type api_token: str
:param net: name of the network, used to differentiate main and test nets
:type net: str, default 'main'
"""
self.address = address
self.nt_type = nt_type
self.client = Client(api_token, self.nt_type)
self.net = net
self.client = Client(api_token, self.nt_type, self.net)
self.db = ScanDataBase()

def update_transactions(self, tr_type: TRANSACTION):
Expand All @@ -35,7 +38,7 @@ def update_transactions(self, tr_type: TRANSACTION):
:return: None
:rtype: None
"""
last_block = self.db.get_last_block_number(self.address, self.nt_type, tr_type)
last_block = self.db.get_last_block_number(self.address, self.nt_type, self.net, tr_type)
if tr_type == TRANSACTION.NORMAL:
new_transactions = self.client.get_normal_transactions(self.address, start_block=last_block + 1)
elif tr_type == TRANSACTION.INTERNAL:
Expand All @@ -46,7 +49,7 @@ def update_transactions(self, tr_type: TRANSACTION):
new_transactions = self.client.get_erc721_transactions(self.address, start_block=last_block + 1)
else:
raise ValueError(f"unknown transaction type: {tr_type}")
self.db.add_transactions(self.address, self.nt_type, tr_type, new_transactions)
self.db.add_transactions(self.address, self.nt_type, self.net, tr_type, new_transactions)

def update_all_transactions(self):
"""
Expand Down Expand Up @@ -74,4 +77,4 @@ def get_transactions(self, tr_type: TRANSACTION):
:return: list of transactions
:rtype: List[Dict]
"""
return self.db.get_transactions(self.address, self.nt_type, tr_type)
return self.db.get_transactions(self.address, self.nt_type, self.net, tr_type)
2 changes: 1 addition & 1 deletion ScanWatch/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__author__ = 'EtWnn'
__version__ = '0.1.1'
__version__ = '0.1.2'

from ScanWatch.ScanManager import ScanManager
18 changes: 12 additions & 6 deletions ScanWatch/storage/ScanDataBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,45 +19,49 @@ def __init__(self, name: str = 'scan_db'):
"""
super().__init__(name)

def add_transactions(self, address: str, nt_type: NETWORK, tr_type: TRANSACTION, transactions: List[Dict]):
def add_transactions(self, address: str, nt_type: NETWORK, net: str, tr_type: TRANSACTION, transactions: List[Dict]):
"""
Add a list of transactions to the database
:param address: address involved in the transaction
:type address: str
:param nt_type: type of network
:type nt_type: NETWORK
:param net: name of the network, used to differentiate main and test nets
:type net: str
:param tr_type: type of the transaction to record
:type tr_type: TRANSACTION
:param transactions: list of the transaction to record
:type transactions: List[Dict]
:return: None
:rtype: None
"""
table = get_transaction_table(address, nt_type, tr_type)
table = get_transaction_table(address, nt_type, net, tr_type)
for transaction in transactions:
row = table.dict_to_tuple(transaction)
self.add_row(table, row, auto_commit=False)
self.commit()

def get_transactions(self, address: str, nt_type: NETWORK, tr_type: TRANSACTION) -> List[Dict]:
def get_transactions(self, address: str, nt_type: NETWORK, net: str, tr_type: TRANSACTION) -> List[Dict]:
"""
Return the List of the transactions recorded in the database
:param address: address involved in the transactions
:type address: str
:param nt_type: type of network
:type nt_type: NETWORK
:param net: name of the network, used to differentiate main and test nets
:type net: str
:param tr_type: type of the transaction to fetch
:type tr_type: TRANSACTION
:return: list of the transaction recorded
:rtype: List[Dict]
"""
table = get_transaction_table(address, nt_type, tr_type)
table = get_transaction_table(address, nt_type, net, tr_type)
rows = self.get_all_rows(table)
return [table.tuple_to_dict(row) for row in rows]

def get_last_block_number(self, address: str, nt_type: NETWORK, tr_type: TRANSACTION) -> int:
def get_last_block_number(self, address: str, nt_type: NETWORK, net: str, tr_type: TRANSACTION) -> int:
"""
Return the last block number seen in recorded transactions (per address, type of transaction and network)
If None are found, return 0
Expand All @@ -66,12 +70,14 @@ def get_last_block_number(self, address: str, nt_type: NETWORK, tr_type: TRANSAC
:type address: str
:param nt_type: type of network
:type nt_type: NETWORK
:param net: name of the network, used to differentiate main and test nets
:type net: str
:param tr_type: type of the transaction to fetch
:type tr_type: TRANSACTION
:return: last block number
:rtype: int
"""
table = get_transaction_table(address, nt_type, tr_type)
table = get_transaction_table(address, nt_type, net, tr_type)
selection = f"MAX({table.blockNumber})"
result = self.get_conditions_rows(table, selection=selection)
default = 0
Expand Down
9 changes: 7 additions & 2 deletions ScanWatch/storage/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,16 @@ def get_normal_transaction_table(address: str, scan_type: NETWORK):
return Table(f"{scan_type}_{address}_normal_transaction", rows, row_types)


def get_transaction_table(address: str, nt_type: NETWORK, tr_type: TRANSACTION):
def get_transaction_table(address: str, nt_type: NETWORK, net: str, tr_type: TRANSACTION):
"""
Return the table used to store the transactions depending on the address, network type and transaction type
:param address: address of the transactions
:type address: str
:param nt_type: type of network
:type nt_type: NETWORK
:param net: name of the network, used to differentiate main and test nets
:type net: str
:param tr_type: type of the transaction to record
:type tr_type: TRANSACTION
:return: corresponding table
Expand Down Expand Up @@ -212,4 +214,7 @@ def get_transaction_table(address: str, nt_type: NETWORK, tr_type: TRANSACTION):
raise ValueError(f"unknown transaction type: {tr_type}")

row_types = len(rows) * ['TEXT']
return Table(f"{nt_type.name.lower()}_{tr_type.name.lower()}_{address}_transaction", rows, row_types)
pre_name = f"{nt_type.name.lower()}_{tr_type.name.lower()}"
if net != "main": # backward compatibility
pre_name += f"_{net}"
return Table(pre_name + f"_{address}_transaction", rows, row_types)

0 comments on commit 28f1b44

Please sign in to comment.