Skip to content

Commit 96942af

Browse files
committed
changed Tokens class to take contract address instead of token name.
1 parent dc375dd commit 96942af

25 files changed

+451
-54
lines changed

build/lib/etherscan/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__author__ = 'Corey Petty'

build/lib/etherscan/accounts.py

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
from .client import Client
2+
import re
3+
4+
5+
class Account(Client):
6+
def __init__(self, address=Client.dao_address, api_key='YourApiKeyToken'):
7+
Client.__init__(self, address=address, api_key=api_key)
8+
self.url_dict[self.MODULE] = 'account'
9+
10+
def get_balance(self):
11+
self.url_dict[self.ACTION] = 'balance'
12+
self.url_dict[self.TAG] = 'latest'
13+
self.build_url()
14+
req = self.connect()
15+
return req['result']
16+
17+
def get_balance_multiple(self):
18+
self.url_dict[self.ACTION] = 'balancemulti'
19+
self.url_dict[self.TAG] = 'latest'
20+
self.build_url()
21+
req = self.connect()
22+
return req['result']
23+
24+
def get_transaction_page(self, page=1, offset=10000, sort='asc', internal=False) -> list:
25+
"""
26+
Get a page of transactions, each transaction returns list of dict with keys:
27+
nonce
28+
hash
29+
cumulativeGasUsed
30+
gasUsed
31+
timeStamp
32+
blockHash
33+
value (in wei)
34+
input
35+
gas
36+
isInternalTx
37+
contractAddress
38+
confirmations
39+
gasPrice
40+
transactionIncex
41+
to
42+
from
43+
isError
44+
blockNumber
45+
46+
sort options:
47+
'asc' -> ascending order
48+
'des' -> descending order
49+
50+
internal options:
51+
True -> Gets the internal transactions of a smart contract
52+
False -> (default) get normal external transactions
53+
"""
54+
if internal:
55+
self.url_dict[self.ACTION] = 'txlistinternal'
56+
else:
57+
self.url_dict[self.ACTION] = 'txlist'
58+
self.url_dict[self.PAGE] = str(page)
59+
self.url_dict[self.OFFSET] = str(offset)
60+
self.url_dict[self.SORT] = sort
61+
self.build_url()
62+
req = self.connect()
63+
return req['result']
64+
65+
def get_all_transactions(self, offset=10000, sort='asc', internal=False) -> list:
66+
if internal:
67+
self.url_dict[self.ACTION] = 'txlistinternal'
68+
else:
69+
self.url_dict[self.ACTION] = 'txlist'
70+
self.url_dict[self.PAGE] = str(1)
71+
self.url_dict[self.OFFSET] = str(offset)
72+
self.url_dict[self.SORT] = sort
73+
self.build_url()
74+
75+
trans_list = []
76+
while True:
77+
self.build_url()
78+
req = self.connect()
79+
if "No transactions found" in req['message']:
80+
print("Total number of transactions: {}".format(len(trans_list)))
81+
self.page = ''
82+
return trans_list
83+
else:
84+
trans_list += req['result']
85+
# Find any character block that is a integer of any length
86+
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])
87+
print("page {} added".format(page_number[0]))
88+
self.url_dict[self.PAGE] = str(int(page_number[0]) + 1)
89+
90+
def get_blocks_mined_page(self, blocktype='blocks', page=1, offset=10000) -> list:
91+
"""
92+
Get a page of blocks mined by given address, returns list of dict with keys:
93+
blockReward (in wei)
94+
blockNumber
95+
timeStamp
96+
97+
blocktype options:
98+
'blocks' -> full blocks only
99+
'uncles' -> uncles only
100+
"""
101+
self.url_dict[self.ACTION] = 'getminedblocks'
102+
self.url_dict[self.BLOCK_TYPE] = blocktype
103+
self.url_dict[self.PAGE] = str(page)
104+
self.url_dict[self.OFFSET] = str(offset)
105+
self.build_url()
106+
req = self.connect()
107+
return req['result']
108+
109+
def get_all_blocks_mined(self, blocktype='blocks', offset=10000) -> list:
110+
self.url_dict[self.ACTION] = 'getminedblocks'
111+
self.url_dict[self.BLOCK_TYPE] = blocktype
112+
self.url_dict[self.PAGE] = str(1)
113+
self.url_dict[self.OFFSET] = str(offset)
114+
blocks_list = []
115+
while True:
116+
self.build_url()
117+
req = self.connect()
118+
print(req['message'])
119+
if "No transactions found" in req['message']:
120+
print("Total number of blocks mined: {}".format(len(blocks_list)))
121+
return blocks_list
122+
else:
123+
blocks_list += req['result']
124+
# Find any character block that is a integer of any length
125+
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])
126+
print("page {} added".format(page_number[0]))
127+
self.url_dict[self.PAGE] = str(int(page_number[0]) + 1)
128+
129+
def get_internal_by_hash(self, tx_hash=''):
130+
"""
131+
Currently not implemented
132+
:return:
133+
"""
134+
pass
135+
136+
def update_transactions(self, address, trans):
137+
"""
138+
Gets last page of transactions (last 10k trans) and updates current trans book (book)
139+
"""
140+
pass

build/lib/etherscan/client.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import requests
2+
import collections
3+
4+
# Assume user puts his API key in the api_key.json file under variable name "key"
5+
class Client(object):
6+
dao_address = '0xbb9bc244d798123fde783fcc1c72d3bb8c189413'
7+
8+
# Constants
9+
PREFIX = 'https://api.etherscan.io/api?'
10+
MODULE = 'module='
11+
ACTION = '&action='
12+
CONTRACT_ADDRESS = '&contractaddress='
13+
ADDRESS = '&address='
14+
OFFSET = '&offset='
15+
PAGE = '&page='
16+
SORT = '&sort='
17+
BLOCK_TYPE = '&blocktype='
18+
TO = '&to='
19+
VALUE = '&value='
20+
DATA = '&data='
21+
POSITION = '&='
22+
HEX = '&hex='
23+
GAS_PRICE = '&gasPrice='
24+
GAS = '&gas='
25+
START_BLOCK = '&startblock='
26+
END_BLOCK = '&endblock='
27+
BLOCKNO = '&blockno='
28+
TXHASH = '&txhash='
29+
TAG = '&tag='
30+
BOOLEAN = '&boolean='
31+
INDEX = '&index='
32+
API_KEY = '&apikey='
33+
34+
url_dict = {}
35+
36+
def __init__(self, address, api_key=''):
37+
self.http = requests.session()
38+
self.url_dict = collections.OrderedDict([
39+
40+
(self.MODULE, ''),
41+
(self.ADDRESS, ''),
42+
(self.OFFSET, ''),
43+
(self.PAGE, ''),
44+
(self.SORT, ''),
45+
(self.BLOCK_TYPE, ''),
46+
(self.TO, ''),
47+
(self.VALUE, ''),
48+
(self.DATA, ''),
49+
(self.POSITION, ''),
50+
(self.HEX, ''),
51+
(self.GAS_PRICE, ''),
52+
(self.GAS, ''),
53+
(self.START_BLOCK, ''),
54+
(self.END_BLOCK, ''),
55+
(self.BLOCKNO, ''),
56+
(self.TXHASH, ''),
57+
(self.TAG, ''),
58+
(self.BOOLEAN, ''),
59+
(self.INDEX, ''),
60+
(self.API_KEY, api_key)]
61+
)
62+
63+
# self.url_dict[API_KEY] = str(api_key)
64+
self.check_and_get_api()
65+
# self.key = self.URL_BASES['key'] + self.API_KEY
66+
67+
if (len(address) > 20) and (type(address) == list):
68+
print("Etherscan only takes 20 addresses at a time")
69+
quit()
70+
elif (type(address) == list) and (len(address) <= 20):
71+
self.url_dict[self.ADDRESS] = ','.join(address)
72+
else:
73+
self.url_dict[self.ADDRESS] = address
74+
75+
def build_url(self):
76+
self.url = self.PREFIX + ''.join([param + val if val else '' for param, val in self.url_dict.items()])
77+
78+
def connect(self):
79+
# TODO: deal with "unknown exception" error
80+
try:
81+
req = self.http.get(self.url)
82+
except requests.exceptions.ConnectionError:
83+
print("Connection refused")
84+
exit()
85+
86+
if req.status_code == 200:
87+
# Check for empty response
88+
if req.text:
89+
if req.json()['status'] == '1':
90+
return req.json()
91+
else:
92+
print(req.json()['message'])
93+
exit()
94+
else:
95+
print("Invalid Request")
96+
exit()
97+
else:
98+
print("Problem with connection, status code: ", req.status_code)
99+
exit()
100+
101+
def check_and_get_api(self):
102+
if self.url_dict[self.API_KEY]: # Check if api_key is empty string
103+
pass
104+
else:
105+
self.url_dict[self.API_KEY] = input('Please type your EtherScan.io API key: ')

build/lib/etherscan/contracts.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from .client import Client
2+
3+
4+
class Contract(Client):
5+
def __init__(self, address=Client.dao_address, api_key='YourApiKeyToken'):
6+
Client.__init__(self, address=address, api_key=api_key)
7+
self.url_dict[self.MODULE] = 'contract'
8+
9+
def get_abi(self):
10+
self.url_dict[self.ACTION] = 'getabi'
11+
self.build_url()
12+
req = self.connect()
13+
return req['result']

build/lib/etherscan/stats.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from .client import Client
2+
3+
4+
class Stats(Client):
5+
def __init__(self, api_key='YourApiKeyToken'):
6+
Client.__init__(self, address='', api_key=api_key)
7+
self.url_dict[self.MODULE] = 'stats'
8+
9+
def get_total_ether_supply(self):
10+
self.url_dict[self.ACTION] = 'ethsupply'
11+
self.build_url()
12+
req = self.connect()
13+
return req['result']
14+
15+
def get_ether_last_price(self):
16+
self.url_dict[self.ACTION] = 'ethprice'
17+
self.build_url()
18+
req = self.connect()
19+
return req['result']

build/lib/etherscan/tokens.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from .client import Client
2+
3+
4+
class Tokens(Client):
5+
def __init__(self, contract_address, api_key='YourApiKeyToken'):
6+
Client.__init__(self, address='', api_key=api_key)
7+
# self.url_dict[self.TOKEN_NAME] = tokenname
8+
self.url_dict[self.CONTRACT_ADDRESS] = contract_address
9+
10+
def get_total_supply(self):
11+
self.url_dict[self.ACTION] = 'tokensupply'
12+
self.url_dict[self.MODULE] = 'stats'
13+
self.build_url()
14+
req = self.connect()
15+
return req['result']
16+
17+
def get_token_balance(self, address):
18+
self.url_dict[self.ADDRESS] = address
19+
self.url_dict[self.MODULE] = 'account'
20+
self.url_dict[self.ACTION] = 'tokenbalance'
21+
self.build_url()
22+
req = self.connect()
23+
return req['result']

build/lib/examples/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__author__ = 'Corey Petty'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__author__ = 'Corey Petty'
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from etherscan.accounts import Account
2+
import json
3+
4+
with open('../../api_key.json', mode='r') as key_file:
5+
key = json.loads(key_file.read())['key']
6+
7+
address = '0x2a65aca4d5fc5b5c859090a6c34d164135398226'
8+
9+
api = Account(address=address, api_key=key)
10+
blocks = api.get_all_blocks_mined(offset=10000, blocktype='uncles')
11+
print(blocks)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from etherscan.accounts import Account
2+
import json
3+
4+
with open('../../api_key.json', mode='r') as key_file:
5+
key = json.loads(key_file.read())['key']
6+
7+
# address = ['0xddbd2b932c763ba5b1b7ae3b362eac3e8d40121a', '0xddbd2b932c763ba5b1b7ae3b362eac3e8d40121a']
8+
address = '0x49edf201c1e139282643d5e7c6fb0c7219ad1db7'
9+
10+
api = Account(address=address, api_key=key)
11+
transactions = api.get_all_transactions(offset=10000, sort='asc', internal=True)
12+
13+
print(transactions[0])

0 commit comments

Comments
 (0)