1+ # coding: utf-8
2+ import collections
3+
4+ import requests
5+
6+
7+ class ClientException (Exception ):
8+ """Unhandled API client exception"""
9+ message = 'unhandled error'
10+
11+ def __init__ (self , message = None ):
12+ if message is not None :
13+ self .message = message
14+
15+ def __unicode__ (self ):
16+ return u'<Err: {0.message}>' .format (self )
17+
18+ __str__ = __unicode__
19+
20+
21+ class ConnectionRefused (ClientException ):
22+ """Connection refused by remote host"""
23+
24+
25+ class EmptyResponse (ClientException ):
26+ """Empty response from API"""
27+
28+
29+ class BadRequest (ClientException ):
30+ """Invalid request passed"""
31+
32+
33+ # Assume user puts his API key in the api_key.json file under variable name "key"
34+ class Client (object ):
35+ dao_address = '0xbb9bc244d798123fde783fcc1c72d3bb8c189413'
36+
37+ # Constants
38+ PREFIX = 'https://api-ropsten.etherscan.io/api?' # TESTNET
39+ MODULE = 'module='
40+ ACTION = '&action='
41+ CONTRACT_ADDRESS = '&contractaddress='
42+ ADDRESS = '&address='
43+ OFFSET = '&offset='
44+ PAGE = '&page='
45+ SORT = '&sort='
46+ BLOCK_TYPE = '&blocktype='
47+ TO = '&to='
48+ VALUE = '&value='
49+ DATA = '&data='
50+ POSITION = '&='
51+ HEX = '&hex='
52+ GAS_PRICE = '&gasPrice='
53+ GAS = '&gas='
54+ START_BLOCK = '&startblock='
55+ END_BLOCK = '&endblock='
56+ BLOCKNO = '&blockno='
57+ TXHASH = '&txhash='
58+ TAG = '&tag='
59+ BOOLEAN = '&boolean='
60+ INDEX = '&index='
61+ API_KEY = '&apikey='
62+
63+ url_dict = {}
64+
65+ def __init__ (self , address , api_key = '' ):
66+ self .http = requests .session ()
67+ self .url_dict = collections .OrderedDict ([
68+
69+ (self .MODULE , '' ),
70+ (self .ADDRESS , '' ),
71+ (self .OFFSET , '' ),
72+ (self .PAGE , '' ),
73+ (self .SORT , '' ),
74+ (self .BLOCK_TYPE , '' ),
75+ (self .TO , '' ),
76+ (self .VALUE , '' ),
77+ (self .DATA , '' ),
78+ (self .POSITION , '' ),
79+ (self .HEX , '' ),
80+ (self .GAS_PRICE , '' ),
81+ (self .GAS , '' ),
82+ (self .START_BLOCK , '' ),
83+ (self .END_BLOCK , '' ),
84+ (self .BLOCKNO , '' ),
85+ (self .TXHASH , '' ),
86+ (self .TAG , '' ),
87+ (self .BOOLEAN , '' ),
88+ (self .INDEX , '' ),
89+ (self .API_KEY , api_key )]
90+ )
91+
92+ # self.url_dict[API_KEY] = str(api_key)
93+ self .check_and_get_api ()
94+ # self.key = self.URL_BASES['key'] + self.API_KEY
95+
96+ if (len (address ) > 20 ) and (type (address ) == list ):
97+ raise BadRequest ("Etherscan only takes 20 addresses at a time" )
98+ elif (type (address ) == list ) and (len (address ) <= 20 ):
99+ self .url_dict [self .ADDRESS ] = ',' .join (address )
100+ else :
101+ self .url_dict [self .ADDRESS ] = address
102+
103+ def build_url (self ):
104+ self .url = self .PREFIX + '' .join ([param + val if val else '' for param , val in self .url_dict .items ()])
105+
106+ def connect (self ):
107+ # TODO: deal with "unknown exception" error
108+ try :
109+ req = self .http .get (self .url )
110+ except requests .exceptions .ConnectionError :
111+ raise ConnectionRefused
112+
113+ if req .status_code == 200 :
114+ # Check for empty response
115+ if req .text :
116+ data = req .json ()
117+ status = data .get ('status' )
118+ if status == '1' or self .check_keys_api (data ):
119+ return data
120+ else :
121+ raise EmptyResponse (data .get ('message' , 'no message' ))
122+ raise BadRequest ("Problem with connection, status code: %s" % req .status_code )
123+
124+ def check_and_get_api (self ):
125+ if self .url_dict [self .API_KEY ]: # Check if api_key is empty string
126+ pass
127+ else :
128+ self .url_dict [self .API_KEY ] = input ('Please type your EtherScan.io API key: ' )
129+
130+ def check_keys_api (self , data ):
131+ return all (k in data for k in ('jsonrpc' , 'id' , 'result' ))
132+
0 commit comments