defi-state-querier 0.4.30__py3-none-any.whl → 0.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,549 @@
1
+ import itertools
2
+
3
+ from query_state_lib.base.mappers.eth_call_balance_of_mapper import EthCallBalanceOf
4
+ from query_state_lib.base.mappers.get_balance_mapper import GetBalance
5
+ from query_state_lib.client.client_querier import ClientQuerier
6
+ from web3 import Web3, HTTPProvider
7
+ from web3.middleware import geth_poa_middleware
8
+
9
+ from defi_services.abis.dex.pancakeswap.pancakeswap_lp_token_abi import LP_TOKEN_ABI
10
+ from defi_services.abis.token.erc20_abi import ERC20_ABI
11
+ from defi_services.abis.token.erc721_abi import ERC721_ABI
12
+ from defi_services.constants.network_constants import NATIVE_TOKEN
13
+ from defi_services.services.eth.eth_services import EthService
14
+ from defi_services.services.multicall.batch_queries_service import add_rpc_call, decode_data_response_ignore_error
15
+ from defi_services.utils.logger_utils import get_logger
16
+
17
+ logger = get_logger('State Query Service')
18
+
19
+
20
+ class StateQueryService:
21
+ def __init__(self, provider_uri):
22
+ self._w3 = Web3(HTTPProvider(provider_uri))
23
+ self._w3.middleware_onion.inject(geth_poa_middleware, layer=0)
24
+
25
+ self.client_querier = ClientQuerier(provider_url=provider_uri)
26
+
27
+ def get_web3(self):
28
+ return self._w3
29
+
30
+ def to_checksum(self, address):
31
+ return self._w3.to_checksum_address(address)
32
+
33
+ def get_contract(self, address, abi):
34
+ try:
35
+ return self._w3.eth.contract(self.to_checksum(address), abi=abi)
36
+ except TypeError:
37
+ print('a')
38
+
39
+ def is_contract(self, address):
40
+ code = self._w3.eth.get_code(self.to_checksum(address))
41
+ code_str = code.hex()
42
+ if code_str == '0x':
43
+ return False
44
+ else:
45
+ return True
46
+
47
+ def decode_tx(self, address, abi, tx_input):
48
+ contract = self.get_contract(address, abi)
49
+ func_obj, func_params = contract.decode_function_input(tx_input)
50
+ return func_obj, func_params
51
+
52
+ def is_address(self, address):
53
+ return self._w3.is_address(address)
54
+
55
+ def balance_of(self, address, token, abi=ERC20_ABI, block_number='latest'):
56
+ token_contract = self._w3.eth.contract(self._w3.to_checksum_address(token), abi=abi)
57
+ decimals = token_contract.functions.decimals().call()
58
+ balance = token_contract.functions.balanceOf(self._w3.to_checksum_address(address)).call(
59
+ block_identifier=block_number)
60
+ return balance / 10 ** decimals
61
+
62
+ def batch_balance_of(self, address, tokens, block_number: int = 'latest', batch_size=100):
63
+ balances = {}
64
+ tokens = {token['address']: token['decimals'] or 18 for token in tokens}
65
+ rpc_requests = []
66
+ for token in tokens:
67
+ if token != "0x" and token != NATIVE_TOKEN:
68
+ query_id = f'{address}_{token}'
69
+ call_balance_of = EthCallBalanceOf(
70
+ contract_address=Web3.to_checksum_address(token),
71
+ address=Web3.to_checksum_address(address),
72
+ block_number=block_number,
73
+ id=query_id
74
+ )
75
+ else:
76
+ query_id = f"{address}_{NATIVE_TOKEN}"
77
+ call_balance_of = GetBalance(
78
+ address=Web3.to_checksum_address(address),
79
+ block_number=block_number,
80
+ id=query_id
81
+ )
82
+ rpc_requests.append(call_balance_of)
83
+ rpc_responses = self.client_querier.sent_batch_to_provider(rpc_requests, batch_size=batch_size)
84
+ for token, decimals in tokens.items():
85
+ if token == '0x':
86
+ token = NATIVE_TOKEN
87
+ balance = rpc_responses.get(f'{address}_{token}').result or 0
88
+ balance = balance / 10 ** decimals
89
+ balances[token] = balance
90
+
91
+ return balances
92
+
93
+ def batch_balance_of_multiple_addresses(self, addresses, tokens, block_number='latest', batch_size=100):
94
+ tokens_decimals = {token['address']: token.get('decimals') or 18 for token in tokens}
95
+
96
+ rpc_requests = []
97
+ for address, interacted_tokens in addresses.items():
98
+ for token_address in interacted_tokens:
99
+ if token_address != "0x" and token_address != NATIVE_TOKEN:
100
+ query_id = f'{address}_{token_address}'
101
+ call_balance_of = EthCallBalanceOf(
102
+ contract_address=Web3.to_checksum_address(token_address),
103
+ address=Web3.to_checksum_address(address),
104
+ block_number=block_number,
105
+ id=query_id
106
+ )
107
+ else:
108
+ query_id = f"{address}_{NATIVE_TOKEN}"
109
+ call_balance_of = GetBalance(
110
+ address=Web3.to_checksum_address(address),
111
+ block_number=block_number,
112
+ id=query_id
113
+ )
114
+ rpc_requests.append(call_balance_of)
115
+
116
+ rpc_responses = self.client_querier.sent_batch_to_provider(rpc_requests, batch_size=batch_size)
117
+
118
+ results = {}
119
+ for address, interacted_tokens in addresses.items():
120
+ results[address] = {}
121
+ for token_address in interacted_tokens:
122
+ balance = rpc_responses.get(f'{address}_{token_address}').result or 0
123
+
124
+ decimals = tokens_decimals.get(token_address) or 18
125
+ balance = balance / 10 ** decimals
126
+ results[address][token_address] = balance
127
+
128
+ return results, len(rpc_requests)
129
+
130
+ def get_block_number_by_timestamp(self, block_timestamp):
131
+ eth_service = EthService(self._w3)
132
+ block_number = eth_service.get_block_for_timestamp(block_timestamp)
133
+ return block_number
134
+
135
+ def batch_native_balance_of_wallets(self, addresses, blocks, decimals=18, batch_size=100):
136
+ rpc_requests = []
137
+ for address in addresses:
138
+ for block_number in blocks:
139
+ query_id = f"{address}_{block_number}"
140
+ call_balance_of = GetBalance(
141
+ address=Web3.to_checksum_address(address),
142
+ block_number=block_number,
143
+ id=query_id
144
+ )
145
+ rpc_requests.append(call_balance_of)
146
+
147
+ rpc_responses = self.client_querier.sent_batch_to_provider(rpc_requests, batch_size=batch_size)
148
+
149
+ data = {}
150
+ for address in addresses:
151
+ data[address] = {}
152
+ for block_number in blocks:
153
+ balance = rpc_responses.get(f'{address}_{block_number}').result or 0
154
+ balance = balance / 10 ** decimals
155
+ data[address][block_number] = balance
156
+
157
+ return data
158
+
159
+ def batch_balance_of_wallets(self, addresses, tokens, blocks, batch_size=100):
160
+ rpc_requests = []
161
+
162
+ for address, token, block_number in itertools.product(addresses, tokens, blocks):
163
+ token_address = token['address']
164
+ query_id = f'{address}_{token_address}_{block_number}'
165
+ if token_address != "0x" and token_address != NATIVE_TOKEN:
166
+ call_balance_of = EthCallBalanceOf(
167
+ contract_address=Web3.to_checksum_address(token_address),
168
+ address=Web3.to_checksum_address(address),
169
+ block_number=block_number,
170
+ id=query_id
171
+ )
172
+ else:
173
+ call_balance_of = GetBalance(
174
+ address=Web3.to_checksum_address(address),
175
+ block_number=block_number,
176
+ id=query_id
177
+ )
178
+ rpc_requests.append(call_balance_of)
179
+
180
+ rpc_responses = self.client_querier.sent_batch_to_provider(rpc_requests, batch_size=batch_size)
181
+
182
+ data = {}
183
+ for address, token, block_number in itertools.product(addresses, tokens, blocks):
184
+ token_address = token['address']
185
+ query_id = f'{address}_{token_address}_{block_number}'
186
+ balance = rpc_responses.get(query_id).result or 0
187
+
188
+ decimals = token.get('decimals') or 18
189
+
190
+ if address not in data:
191
+ data[address] = {}
192
+ if token_address not in data[address]:
193
+ data[address][token_address] = {}
194
+ data[address][token_address][block_number] = balance / 10 ** decimals
195
+
196
+ return data
197
+
198
+ def batch_balance_of_wallets_block(self, addresses, tokens, block_number='latest', batch_size=100):
199
+ rpc_requests = []
200
+ for address, token in itertools.product(addresses, tokens):
201
+ token_address = token['address']
202
+ query_id = f'{address}_{token_address}_{block_number}'
203
+ if token_address != "0x" and token_address != NATIVE_TOKEN:
204
+ call_balance_of = EthCallBalanceOf(
205
+ contract_address=Web3.to_checksum_address(token_address),
206
+ address=Web3.to_checksum_address(address),
207
+ block_number=block_number,
208
+ id=query_id
209
+ )
210
+ else:
211
+ call_balance_of = GetBalance(
212
+ address=Web3.to_checksum_address(address),
213
+ block_number=block_number,
214
+ id=query_id
215
+ )
216
+ rpc_requests.append(call_balance_of)
217
+
218
+ rpc_responses = self.client_querier.sent_batch_to_provider(rpc_requests, batch_size=batch_size)
219
+
220
+ data = {}
221
+ for address, token in itertools.product(addresses, tokens):
222
+ token_address = token['address']
223
+ query_id = f'{address}_{token_address}_{block_number}'
224
+ balance = rpc_responses.get(query_id).result or 0
225
+ decimals = token.get('decimals') or 18
226
+ if address not in data:
227
+ data[address] = {}
228
+ if token_address not in data[address]:
229
+ data[address][token_address] = {}
230
+ data[address][token_address] = balance / 10 ** decimals
231
+
232
+ return data
233
+
234
+ def batch_balance_of_wallet_info(self, wallet_info: dict, block_number='latest', batch_size=100):
235
+ rpc_requests = []
236
+ for address, tokens in wallet_info.items():
237
+ for token in tokens:
238
+ token_address = token['address']
239
+ query_id = f'{address}_{token_address}_{block_number}'
240
+ if token_address != "0x" and token_address != NATIVE_TOKEN:
241
+ call_balance_of = EthCallBalanceOf(
242
+ contract_address=Web3.to_checksum_address(token_address),
243
+ address=Web3.to_checksum_address(address),
244
+ block_number=block_number,
245
+ id=query_id
246
+ )
247
+ else:
248
+ call_balance_of = GetBalance(
249
+ address=Web3.to_checksum_address(address),
250
+ block_number=block_number,
251
+ id=query_id
252
+ )
253
+ rpc_requests.append(call_balance_of)
254
+
255
+ rpc_responses = self.client_querier.sent_batch_to_provider(rpc_requests, batch_size=batch_size)
256
+
257
+ data = {}
258
+ for address, tokens in wallet_info.items():
259
+ for token in tokens:
260
+ token_address = token['address']
261
+ query_id = f'{address}_{token_address}_{block_number}'
262
+ balance = rpc_responses.get(query_id).result or 0
263
+ decimals = token.get('decimals') or 18
264
+ if address not in data:
265
+ data[address] = {}
266
+ if token_address not in data[address]:
267
+ data[address][token_address] = {}
268
+ data[address][token_address] = balance / 10 ** decimals
269
+
270
+ return data
271
+
272
+ def batch_balance_of_wallet_info_with_block_number(self, wallets_info: list, batch_size=100):
273
+ rpc_requests = []
274
+ for wallet_info in wallets_info:
275
+ address = wallet_info['address']
276
+ tokens = wallet_info.get('tokens', [])
277
+ block_number = wallet_info.get('block_number', 'latest')
278
+
279
+ for token in tokens:
280
+ token_address = token['address']
281
+ query_id = f'{address}_{token_address}_{block_number}'
282
+ if token_address != "0x" and token_address != NATIVE_TOKEN:
283
+ call_balance_of = EthCallBalanceOf(
284
+ contract_address=Web3.to_checksum_address(token_address),
285
+ address=Web3.to_checksum_address(address),
286
+ block_number=block_number,
287
+ id=query_id
288
+ )
289
+ else:
290
+ call_balance_of = GetBalance(
291
+ address=Web3.to_checksum_address(address),
292
+ block_number=block_number,
293
+ id=query_id
294
+ )
295
+ rpc_requests.append(call_balance_of)
296
+
297
+ rpc_responses = self.client_querier.sent_batch_to_provider(rpc_requests, batch_size=batch_size)
298
+
299
+ data = {}
300
+ for wallet_info in wallets_info:
301
+ address = wallet_info['address']
302
+ tokens = wallet_info.get('tokens', [])
303
+ block_number = wallet_info.get('block_number', 'latest')
304
+
305
+ for token in tokens:
306
+ token_address = token['address']
307
+ query_id = f'{address}_{token_address}_{block_number}'
308
+ balance = rpc_responses.get(query_id).result or 0
309
+ decimals = token.get('decimals')
310
+ if decimals is None:
311
+ continue
312
+
313
+ if address not in data:
314
+ data[address] = {}
315
+ if token_address not in data[address]:
316
+ data[address][token_address] = {}
317
+ data[address][token_address] = balance / 10 ** decimals
318
+
319
+ return data
320
+
321
+ def recheck_liquidity_pool_v2_reserves(self, liquidity_pools: list, batch_size=100):
322
+ list_rpc_call = []
323
+ list_call_id = []
324
+
325
+ for liquidity_pool in liquidity_pools:
326
+ address = liquidity_pool['address']
327
+ block_number = liquidity_pool.get('block_number', 'latest')
328
+
329
+ add_rpc_call(
330
+ abi=LP_TOKEN_ABI, contract_address=Web3.to_checksum_address(address),
331
+ fn_name="getReserves", block_number=block_number,
332
+ list_call_id=list_call_id, list_rpc_call=list_rpc_call
333
+ )
334
+
335
+ responses = self.client_querier.sent_batch_to_provider(list_rpc_call, batch_size=batch_size)
336
+ decoded_data = decode_data_response_ignore_error(data_responses=responses, list_call_id=list_call_id)
337
+
338
+ data = {}
339
+ for liquidity_pool in liquidity_pools:
340
+ address = liquidity_pool['address']
341
+ tokens = liquidity_pool.get('tokens', [])
342
+ block_number = liquidity_pool.get('block_number', 'latest')
343
+
344
+ reserves = decoded_data.get(f'getReserves_{address}_{block_number}'.lower())
345
+ if not reserves:
346
+ continue
347
+ for token in tokens:
348
+ token_address = token['address']
349
+ balance = reserves[token['idx']]
350
+ decimals = token.get('decimals')
351
+ if decimals is None:
352
+ continue
353
+
354
+ if address not in data:
355
+ data[address] = {}
356
+ if token_address not in data[address]:
357
+ data[address][token_address] = {}
358
+ data[address][token_address] = balance / 10 ** decimals
359
+
360
+ return data
361
+
362
+ def batch_total_supply_pool_info_with_block_number(self, liquidity_pools: list, batch_size=100):
363
+ list_rpc_call = []
364
+ list_call_id = []
365
+ for liquidity_pool in liquidity_pools:
366
+ address = liquidity_pool['address']
367
+ block_number = liquidity_pool['block_number']
368
+
369
+ add_rpc_call(
370
+ abi=LP_TOKEN_ABI, contract_address=Web3.to_checksum_address(address),
371
+ fn_name="totalSupply", block_number=block_number,
372
+ list_call_id=list_call_id, list_rpc_call=list_rpc_call
373
+ )
374
+ add_rpc_call(
375
+ abi=LP_TOKEN_ABI, contract_address=Web3.to_checksum_address(address),
376
+ fn_name="decimals", block_number="latest",
377
+ list_call_id=list_call_id, list_rpc_call=list_rpc_call
378
+ )
379
+ try:
380
+ responses = self.client_querier.sent_batch_to_provider(list_rpc_call, batch_size=batch_size)
381
+ decoded_data = decode_data_response_ignore_error(data_responses=responses, list_call_id=list_call_id)
382
+ except Exception as ex:
383
+ err_detail = str(ex)
384
+ if err_detail.strip().startswith('Response data err'):
385
+ return
386
+ raise ex
387
+ data = {}
388
+ for liquidity_pool in liquidity_pools:
389
+ try:
390
+ address = liquidity_pool['address']
391
+ block_number = liquidity_pool['block_number']
392
+ total_supply = decoded_data.get(f'totalSupply_{address}_{block_number}'.lower())
393
+ decimals = decoded_data.get(f'decimals_{address}_latest'.lower())
394
+ data[address] = {
395
+ "liquidityAmount": total_supply / 10 ** decimals,
396
+ 'decimals': decimals,
397
+ }
398
+
399
+ except Exception:
400
+ continue
401
+
402
+ return data
403
+
404
+ def batch_nfts_info(self, addresses, batch_size=100):
405
+ list_rpc_call = []
406
+ list_call_id = []
407
+ for address in addresses:
408
+ add_rpc_call(
409
+ abi=ERC721_ABI, contract_address=Web3.to_checksum_address(address),
410
+ fn_name="name", block_number='latest',
411
+ list_call_id=list_call_id, list_rpc_call=list_rpc_call
412
+ )
413
+
414
+ add_rpc_call(
415
+ abi=ERC721_ABI, contract_address=Web3.to_checksum_address(address),
416
+ fn_name="symbol", block_number='latest',
417
+ list_call_id=list_call_id, list_rpc_call=list_rpc_call
418
+ )
419
+
420
+ responses = self.client_querier.sent_batch_to_provider(list_rpc_call, batch_size=batch_size)
421
+ decoded_data = decode_data_response_ignore_error(data_responses=responses, list_call_id=list_call_id)
422
+
423
+ data = {}
424
+ for address in addresses:
425
+ query_name_id = f'name_{address}_latest'
426
+ query_symbol_id = f'symbol_{address}_latest'
427
+
428
+ name = decoded_data.get(query_name_id)
429
+ symbol = decoded_data.get(query_symbol_id)
430
+ if name and symbol:
431
+ data[address] = {
432
+ "name": name,
433
+ "symbol": symbol
434
+ }
435
+
436
+ return data
437
+
438
+ def batch_liquidity_pools_tokens(self, liquidity_pools, batch_size=100):
439
+ list_rpc_call = []
440
+ list_call_id = []
441
+ for liquidity_pool in liquidity_pools:
442
+ address = liquidity_pool['address']
443
+
444
+ add_rpc_call(
445
+ abi=LP_TOKEN_ABI, contract_address=Web3.to_checksum_address(address),
446
+ fn_name="token0", block_number="latest",
447
+ list_call_id=list_call_id, list_rpc_call=list_rpc_call
448
+ )
449
+ add_rpc_call(
450
+ abi=LP_TOKEN_ABI, contract_address=Web3.to_checksum_address(address),
451
+ fn_name="token1", block_number="latest",
452
+ list_call_id=list_call_id, list_rpc_call=list_rpc_call
453
+ )
454
+ add_rpc_call(
455
+ abi=LP_TOKEN_ABI, contract_address=Web3.to_checksum_address(address),
456
+ fn_name="factory", block_number="latest",
457
+ list_call_id=list_call_id, list_rpc_call=list_rpc_call
458
+ )
459
+
460
+ try:
461
+ responses = self.client_querier.sent_batch_to_provider(list_rpc_call, batch_size=batch_size)
462
+ decoded_data = decode_data_response_ignore_error(data_responses=responses, list_call_id=list_call_id)
463
+ except Exception as ex:
464
+ err_detail = str(ex)
465
+ if err_detail.strip().startswith('Response data err'):
466
+ return
467
+ raise ex
468
+
469
+ for liquidity_pool in liquidity_pools:
470
+ address = liquidity_pool['address']
471
+
472
+ token0_address = decoded_data.get(f'token0_{address}_latest'.lower())
473
+ token1_address = decoded_data.get(f'token1_{address}_latest'.lower())
474
+ factory = decoded_data.get(f'factory_{address}_latest'.lower())
475
+
476
+ if token0_address and token1_address:
477
+ liquidity_pool.update({
478
+ "address": address,
479
+ "factoryAddress": factory,
480
+ "tokens": [
481
+ {
482
+ "idx": 0,
483
+ "address": token0_address.lower()
484
+ },
485
+ {
486
+ "idx": 1,
487
+ "address": token1_address.lower()
488
+ }
489
+ ]
490
+ })
491
+
492
+ return liquidity_pools
493
+
494
+ def batch_liquidity_pools_info(self, liquidity_pools, batch_size=100):
495
+ list_rpc_call = []
496
+ list_call_id = []
497
+ for liquidity_pool in liquidity_pools:
498
+ address = liquidity_pool['address']
499
+ block_number = liquidity_pool['block_number']
500
+
501
+ for token in liquidity_pool.get('tokens', []):
502
+ add_rpc_call(
503
+ abi=ERC20_ABI, contract_address=Web3.to_checksum_address(token['address']),
504
+ fn_name="decimals", block_number='latest',
505
+ list_call_id=list_call_id, list_rpc_call=list_rpc_call
506
+ )
507
+ add_rpc_call(
508
+ abi=ERC20_ABI, contract_address=Web3.to_checksum_address(token['address']),
509
+ fn_name="symbol", block_number='latest',
510
+ list_call_id=list_call_id, list_rpc_call=list_rpc_call
511
+ )
512
+ add_rpc_call(
513
+ abi=ERC20_ABI, contract_address=Web3.to_checksum_address(token['address']),
514
+ fn_name="balanceOf", fn_paras=address, block_number=block_number,
515
+ list_call_id=list_call_id, list_rpc_call=list_rpc_call
516
+ )
517
+
518
+ try:
519
+ responses = self.client_querier.sent_batch_to_provider(list_rpc_call, batch_size=batch_size)
520
+ decoded_data = decode_data_response_ignore_error(data_responses=responses, list_call_id=list_call_id)
521
+ except Exception as ex:
522
+ err_detail = str(ex)
523
+ if err_detail.strip().startswith('Response data err'):
524
+ return
525
+ raise ex
526
+
527
+ for liquidity_pool in liquidity_pools:
528
+ address = liquidity_pool['address']
529
+ block_number = liquidity_pool['block_number']
530
+
531
+ try:
532
+ for token in liquidity_pool.get('tokens', []):
533
+ symbol = decoded_data.get(f'symbol_{token["address"]}_latest'.lower())
534
+ symbol = symbol.upper() if symbol else ""
535
+ decimals = decoded_data.get(f'decimals_{token["address"]}_latest'.lower())
536
+
537
+ liquidity_amount = decoded_data.get(f'balanceOf_{token["address"]}_{address}_{block_number}'.lower(), 0)
538
+ token['liquidityAmount'] = liquidity_amount / 10 ** decimals
539
+ token['symbol'] = symbol
540
+ token['decimals'] = decimals
541
+
542
+ liquidity_pool['symbol'] = ' - '.join([t['symbol'] for t in liquidity_pool.get('tokens', [])])
543
+ except Exception as ex:
544
+ logger.exception(ex)
545
+
546
+ # Add to invalid liquidity pools
547
+ liquidity_pool.pop('tokens')
548
+
549
+ return liquidity_pools
@@ -21,7 +21,7 @@ class TokenServices:
21
21
  def get_data(wallet: str, token: str, decoded_data: dict, block_number: int = "latest", **kwargs):
22
22
  token_prices = kwargs.get("token_prices", {})
23
23
  decimals_key = f"decimals_{token}_{block_number}".lower()
24
- balance_key = f"balanceOf_{wallet}_{token}_{block_number}".lower()
24
+ balance_key = f"balanceOf_{token}_{[wallet]}_{block_number}".lower()
25
25
  if balance_key in decoded_data:
26
26
  balance = decoded_data.get(balance_key) or 0
27
27
  decimals = decoded_data.get(decimals_key) or 18
@@ -50,11 +50,12 @@ class TokenServices:
50
50
  return result
51
51
 
52
52
  def get_function_balance_info(self, wallet: str, token: str, block_number: int = "latest"):
53
- key = f"balanceOf_{wallet}_{token}_{block_number}".lower()
53
+ fn_paras = [wallet]
54
+ key = f"balanceOf_{token}_{fn_paras}_{block_number}".lower()
54
55
  if token == Token.native_token:
55
56
  return {key: self.state_service.get_native_token_balance_info(wallet, block_number)}
56
57
 
57
- return {key: self.state_service.get_function_info(token, ERC20_ABI, "balanceOf", [wallet], block_number)}
58
+ return {key: self.state_service.get_function_info(token, ERC20_ABI, "balanceOf", fn_paras, block_number)}
58
59
 
59
60
  def get_decimals_info(self, token: str, block_number: int = "latest"):
60
61
  decimals_token = token
@@ -0,0 +1,95 @@
1
+ import copy
2
+ import inspect
3
+
4
+
5
+ def flatten_dict(d):
6
+ out = {}
7
+ for key, val in d.items():
8
+ if isinstance(val, dict):
9
+ val = [val]
10
+ if isinstance(val, list):
11
+ array = []
12
+ for subdict in val:
13
+ if not isinstance(subdict, dict):
14
+ array.append(subdict)
15
+ else:
16
+ deeper = flatten_dict(subdict).items()
17
+ out.update({str(key) + '.' + str(key2): val2 for key2, val2 in deeper})
18
+ if array:
19
+ out.update({str(key): array})
20
+ else:
21
+ out[str(key)] = val
22
+ return out
23
+
24
+
25
+ def reverse_flatten_dict(d: dict) -> dict:
26
+ result = {}
27
+ for key, val in d.items():
28
+ nested_keys = key.split('.')
29
+ d_ = result
30
+ for k in nested_keys[:-1]:
31
+ if k not in d_:
32
+ d_[k] = {}
33
+ d_ = d_[k]
34
+ d_[nested_keys[-1]] = val
35
+
36
+ return result
37
+
38
+
39
+ def add_dict(first_dict: dict, second_dict: dict):
40
+ ans_dict = dict()
41
+ for key in first_dict.keys():
42
+ ans_dict[key] = first_dict[key] + second_dict[key]
43
+ return ans_dict
44
+
45
+
46
+ def remove_none_value_dict(a_dict):
47
+ copy_dict = a_dict.copy()
48
+ for key, value in copy_dict.items():
49
+ if value is None:
50
+ a_dict.pop(key)
51
+ return a_dict
52
+
53
+
54
+ def delete_none(_dict):
55
+ """Delete None values recursively from all the dictionaries"""
56
+ for key, value in list(_dict.items()):
57
+ if isinstance(value, dict):
58
+ delete_none(value)
59
+ elif value is None:
60
+ del _dict[key]
61
+ elif isinstance(value, list):
62
+ for v_i in value:
63
+ if isinstance(v_i, dict):
64
+ delete_none(v_i)
65
+
66
+ return _dict
67
+
68
+
69
+ def filter_doc_by_keys(doc, keys):
70
+ doc_ = copy.deepcopy(doc)
71
+ if keys is None:
72
+ return doc_
73
+ return dict(filter(lambda x: x[0] in keys, doc_.items()))
74
+
75
+
76
+ def get_class_constant_keys(cls):
77
+ keys = []
78
+ for attr in inspect.getmembers(cls):
79
+ # to remove private and protected functions
80
+ if not attr[0].startswith('_'):
81
+ # To remove function
82
+ if not inspect.ismethod(attr[1]):
83
+ keys.append(attr[1])
84
+
85
+ return keys
86
+
87
+
88
+ def short_address(address: str, n_start=3, n_end=4):
89
+ if not address:
90
+ return ''
91
+ return address[:n_start + 2] + '...' + address[-n_end:]
92
+
93
+
94
+ def all_equal(array):
95
+ return (not array) or (array.count(array[0]) == len(array))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: defi-state-querier
3
- Version: 0.4.30
3
+ Version: 0.5.1
4
4
  Summary: Calculate apy, apr, and wallet information,... in decentralized applications.
5
5
  Home-page: https://github.com/Centic-io/defi-state-querier
6
6
  Author: Viet-Bang Pham