Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
# Temporary data
.ipynb_checkpoints/
/examples/stats/.ipynb_checkpoints
/.cache/
Binary file added etherscan/__pycache__/__init__.cpython-36.pyc
Binary file not shown.
Binary file added etherscan/__pycache__/accounts.cpython-36.pyc
Binary file not shown.
Binary file added etherscan/__pycache__/client.cpython-36.pyc
Binary file not shown.
Binary file added etherscan/__pycache__/contracts.cpython-36.pyc
Binary file not shown.
Binary file added etherscan/__pycache__/stats.cpython-36.pyc
Binary file not shown.
Binary file added etherscan/__pycache__/tokens.cpython-36.pyc
Binary file not shown.
94 changes: 34 additions & 60 deletions etherscan/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,19 @@
class Account(Client):
def __init__(self, address=Client.dao_address, api_key='YourApiKeyToken'):
Client.__init__(self, address=address, api_key=api_key)
self.module = self.URL_BASES['module'] + 'account'

def make_url(self, call_type=''):
if call_type == 'balance':
self.url = self.URL_BASES['prefix'] \
+ self.module \
+ self.action \
+ self.address \
+ self.tag \
+ self.key
elif call_type == 'transactions':
self.url = self.URL_BASES['prefix'] \
+ self.module \
+ self.action \
+ self.address \
+ self.offset \
+ self.page \
+ self.key
elif call_type == 'blocks':
self.url = self.URL_BASES['prefix'] \
+ self.module \
+ self.action \
+ self.address \
+ self.blocktype \
+ self.offset \
+ self.page \
+ self.key
self.url_dict[self.MODULE] = 'account'

def get_balance(self):
self.action = self.URL_BASES['action'] + 'balance'
self.tag = self.URL_BASES['tag'] + 'latest'
self.make_url(call_type='transactions')
self.url_dict[self.ACTION] = 'balance'
self.url_dict[self.TAG] = 'latest'
self.build_url()
req = self.connect()
return req['result']

def get_balance_multiple(self):
self.action = self.URL_BASES['action'] + 'balancemulti'
self.tag = self.URL_BASES['tag'] + 'latest'
self.make_url(call_type='balance')
self.url_dict[self.ACTION] = 'balancemulti'
self.url_dict[self.TAG] = 'latest'
self.build_url()
req = self.connect()
return req['result']

Expand Down Expand Up @@ -78,29 +52,29 @@ def get_transaction_page(self, page=1, offset=10000, sort='asc', internal=False)
False -> (default) get normal external transactions
"""
if internal:
self.action = self.URL_BASES['action'] + 'txlistinternal'
self.url_dict[self.ACTION] = 'txlistinternal'
else:
self.action = self.URL_BASES['action'] + 'txlist'
self.page = self.URL_BASES['page'] + str(page)
self.offset = self.URL_BASES['offset'] + str(offset)
self.sort = self.URL_BASES['sort'] + sort
self.make_url(call_type='transactions')
self.url_dict[self.ACTION] = 'txlist'
self.url_dict[self.PAGE] = str(page)
self.url_dict[self.OFFSET] = str(offset)
self.url_dict[self.SORT] = sort
self.build_url()
req = self.connect()
return req['result']

def get_all_transactions(self, offset=10000, sort='asc', internal=False) -> list:
if internal:
self.action = self.URL_BASES['action'] + 'txlistinternal'
self.url_dict[self.ACTION] = 'txlistinternal'
else:
self.action = self.URL_BASES['action'] + 'txlist'
self.page = self.URL_BASES['page'] + str(1)
self.offset = self.URL_BASES['offset'] + str(offset)
self.sort = self.URL_BASES['sort'] + sort
self.make_url(call_type='transactions')
self.url_dict[self.ACTION] = 'txlist'
self.url_dict[self.PAGE] = str(1)
self.url_dict[self.OFFSET] = str(offset)
self.url_dict[self.SORT] = sort
self.build_url()

trans_list = []
while True:
self.make_url(call_type='transactions')
self.build_url()
req = self.connect()
if "No transactions found" in req['message']:
print("Total number of transactions: {}".format(len(trans_list)))
Expand All @@ -109,9 +83,9 @@ def get_all_transactions(self, offset=10000, sort='asc', internal=False) -> list
else:
trans_list += req['result']
# Find any character block that is a integer of any length
page_number = re.findall(r'[1-9](?:\d{0,2})(?:,\d{3})*(?:\.\d*[1-9])?|0?\.\d*[1-9]|0', self.page)
page_number = re.findall(r'[1-9](?:\d{0,2})(?:,\d{3})*(?:\.\d*[1-9])?|0?\.\d*[1-9]|0', self.url_dict[self.PAGE])
print("page {} added".format(page_number[0]))
self.page = self.URL_BASES['page'] + str(int(page_number[0]) + 1)
self.url_dict[self.PAGE] = str(int(page_number[0]) + 1)

def get_blocks_mined_page(self, blocktype='blocks', page=1, offset=10000) -> list:
"""
Expand All @@ -124,22 +98,22 @@ def get_blocks_mined_page(self, blocktype='blocks', page=1, offset=10000) -> lis
'blocks' -> full blocks only
'uncles' -> uncles only
"""
self.action = self.URL_BASES['action'] + 'getminedblocks'
self.blocktype = self.URL_BASES['blocktype'] + blocktype
self.page = self.URL_BASES['page'] + str(page)
self.offset = self.URL_BASES['offset'] + str(offset)
self.make_url(call_type='blocks')
self.url_dict[self.ACTION] = 'getminedblocks'
self.url_dict[self.BLOCK_TYPE] = blocktype
self.url_dict[self.PAGE] = str(page)
self.url_dict[self.OFFSET] = str(offset)
self.build_url()
req = self.connect()
return req['result']

def get_all_blocks_mined(self, blocktype='blocks', offset=10000) -> list:
self.action = self.URL_BASES['action'] + 'getminedblocks'
self.blocktype = self.URL_BASES['blocktype'] + blocktype
self.page = self.URL_BASES['page'] + str(1)
self.offset = self.URL_BASES['offset'] + str(offset)
self.url_dict[self.ACTION] = 'getminedblocks'
self.url_dict[self.BLOCK_TYPE] = blocktype
self.url_dict[self.PAGE] = str(1)
self.url_dict[self.OFFSET] = str(offset)
blocks_list = []
while True:
self.make_url(call_type='blocks')
self.build_url()
req = self.connect()
print(req['message'])
if "No transactions found" in req['message']:
Expand All @@ -148,9 +122,9 @@ def get_all_blocks_mined(self, blocktype='blocks', offset=10000) -> list:
else:
blocks_list += req['result']
# Find any character block that is a integer of any length
page_number = re.findall(r'[1-9](?:\d{0,2})(?:,\d{3})*(?:\.\d*[1-9])?|0?\.\d*[1-9]|0', self.page)
page_number = re.findall(r'[1-9](?:\d{0,2})(?:,\d{3})*(?:\.\d*[1-9])?|0?\.\d*[1-9]|0', self.url_dict[self.PAGE])
print("page {} added".format(page_number[0]))
self.page = self.URL_BASES['page'] + str(int(page_number[0]) + 1)
self.url_dict[self.PAGE] = str(int(page_number[0]) + 1)

def get_internal_by_hash(self, tx_hash=''):
"""
Expand Down
95 changes: 66 additions & 29 deletions etherscan/client.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,81 @@
import requests
import json

import collections

# Assume user puts his API key in the api_key.json file under variable name "key"
class Client(object):
dao_address = '0xbb9bc244d798123fde783fcc1c72d3bb8c189413'
URL_BASES = dict(
prefix='https://api.etherscan.io/',
module='api?module=',
action='&action=',
tag='&tag=',
offset='&offset=',
page='&page=',
sort='&sort=',
blocktype='&blocktype=',
key='&apikey=',
address='&address=',
)

def __init__(self, address, api_key='YourApiKeyToken'):
# Constants
PREFIX = 'https://api.etherscan.io/api?'
MODULE = 'module='
ACTION = '&action='
TOKEN_NAME = '&tokenname='
CONTRACT_ADDRESS = '&contractaddress='
ADDRESS = '&address='
OFFSET = '&offset='
PAGE = '&page='
SORT = '&sort='
BLOCK_TYPE = '&blocktype='
TO = '&to='
VALUE = '&value='
DATA = '&data='
POSITION = '&='
HEX = '&hex='
GAS_PRICE = '&gasPrice='
GAS = '&gas='
START_BLOCK = '&startblock='
END_BLOCK = '&endblock='
BLOCKNO = '&blockno='
TXHASH = '&txhash='
TAG = '&tag='
BOOLEAN = '&boolean='
INDEX = '&index='
API_KEY = '&apikey='

url_dict = {}

def __init__(self, address, api_key=''):
self.http = requests.session()
self.url = ''
self.module = ''
self.action = ''
self.tag = ''
self.offset = ''
self.page = ''
self.sort = ''
self.blocktype = ''
self.url_dict = collections.OrderedDict(
{
self.MODULE: '',
self.ADDRESS: '',
self.OFFSET: '',
self.PAGE: '',
self.SORT: '',
self.BLOCK_TYPE: '',
self.TO: '',
self.VALUE: '',
self.DATA: '',
self.POSITION: '',
self.HEX: '',
self.GAS_PRICE: '',
self.GAS: '',
self.START_BLOCK: '',
self.END_BLOCK: '',
self.BLOCKNO: '',
self.TXHASH: '',
self.TAG: '',
self.BOOLEAN: '',
self.INDEX: '',
self.API_KEY: api_key,
})

self.API_KEY = str(api_key)
# self.url_dict[API_KEY] = str(api_key)
self.check_and_get_api()
self.key = self.URL_BASES['key'] + self.API_KEY
# self.key = self.URL_BASES['key'] + self.API_KEY

if (len(address) > 20) and (type(address) == list):
print("Etherscan only takes 20 addresses at a time")
quit()
elif (type(address) == list) and (len(address) <= 20):
self.address = self.URL_BASES['address'] + ','.join(address)
self.url_dict[self.ADDRESS] = ','.join(address)
else:
self.address = self.URL_BASES['address'] + address
self.url_dict[self.ADDRESS] = address

def build_url(self):
self.url = self.PREFIX + ''.join([param + val if val else '' for param, val in self.url_dict.items()])

def connect(self):
# TODO: deal with "unknown exception" error
Expand All @@ -54,11 +91,11 @@ def connect(self):
print("Invalid Request")
exit()
else:
print("problem with connection, status code: ", req.status_code)
print("Problem with connection, status code: ", req.status_code)
exit()

def check_and_get_api(self):
if self.API_KEY != 'YourApiKeyToken':
if self.url_dict[self.API_KEY]: # Check if api_key is empty string
pass
else:
self.API_KEY = input('Please type your EtherScan.io API key: ')
self.url_dict[self.API_KEY] = input('Please type your EtherScan.io API key: ')
16 changes: 4 additions & 12 deletions etherscan/contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,10 @@
class Contract(Client):
def __init__(self, address=Client.dao_address, api_key='YourApiKeyToken'):
Client.__init__(self, address=address, api_key=api_key)
self.module = self.URL_BASES['module'] + 'contract'

def make_url(self, call_type=''):
if call_type == 'getabi':
self.url = self.URL_BASES['prefix'] \
+ self.module \
+ self.action \
+ self.address \
+ self.key
self.url_dict[self.MODULE] = 'contract'

def get_abi(self):
self.action = self.URL_BASES['action'] + 'getabi'
self.make_url(call_type='getabi')
self.url_dict[self.ACTION] = 'getabi'
self.build_url()
req = self.connect()
return req['result']
return req['result']
17 changes: 5 additions & 12 deletions etherscan/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,16 @@
class Stats(Client):
def __init__(self, api_key='YourApiKeyToken'):
Client.__init__(self, address='', api_key=api_key)
self.module = self.URL_BASES['module'] + 'stats'

def make_url(self, call_type=''):
if call_type == 'stats':
self.url = self.URL_BASES['prefix'] \
+ self.module \
+ self.action \
+ self.key
self.url_dict[self.MODULE] = 'stats'

def get_total_ether_supply(self):
self.action = self.URL_BASES['action'] + 'ethsupply'
self.make_url(call_type='stats')
self.url_dict[self.ACTION] = 'ethsupply'
self.build_url()
req = self.connect()
return req['result']

def get_ether_last_price(self):
self.action = self.URL_BASES['action'] + 'ethprice'
self.make_url(call_type='stats')
self.url_dict[self.ACTION] = 'ethprice'
self.build_url()
req = self.connect()
return req['result']
31 changes: 8 additions & 23 deletions etherscan/tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,19 @@
class Tokens(Client):
def __init__(self, tokenname='TheDAO', api_key='YourApiKeyToken'):
Client.__init__(self, address='', api_key=api_key)
self.tokenname = '&tokenname=' + tokenname

def make_url(self, call_type=''):
if call_type == 'tokensupply':
self.url = self.URL_BASES['prefix'] \
+ self.module \
+ self.action \
+ self.tokenname \
+ self.key
elif call_type == 'tokenbalance':
self.url = self.URL_BASES['prefix'] \
+ self.module \
+ self.action \
+ self.tokenname \
+ self.address \
+ self.key
self.url_dict[self.TOKEN_NAME] = tokenname

def get_total_supply(self):
self.action = self.URL_BASES['action'] + 'tokensupply'
self.module = self.URL_BASES['module'] + 'stats'
self.make_url(call_type='tokensupply')
self.url_dict[self.ACTION] = 'tokensupply'
self.url_dict[self.MODULE] = 'stats'
self.build_url()
req = self.connect()
return req['result']

def get_token_balance(self, address):
self.address = self.URL_BASES['address'] + address
self.module = self.URL_BASES['module'] + 'account'
self.action = self.URL_BASES['action'] + 'tokenbalance'
self.make_url(call_type='tokenbalance')
self.url_dict[self.ADDRESS] = address
self.url_dict[self.MODULE] = 'account'
self.url_dict[self.ACTION] = 'tokenbalance'
self.build_url()
req = self.connect()
return req['result']