defi-state-querier 0.5.26__py3-none-any.whl → 0.5.28__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.
- defi_services/__init__.py +1 -1
- defi_services/constants/chain_constant.py +1 -8
- defi_services/constants/entities/dex_info_constant.py +2 -2
- defi_services/constants/entities/dex_services.py +1 -13
- defi_services/constants/entities/lending_constant.py +5 -11
- defi_services/constants/entities/lending_services.py +4 -31
- defi_services/constants/entities/vault_constant.py +2 -2
- defi_services/constants/entities/vault_services.py +1 -7
- defi_services/constants/network_constants.py +361 -20
- defi_services/constants/token_constant.py +1 -3
- defi_services/jobs/processors/cosmos_state_processor.py +2 -3
- defi_services/jobs/processors/ton_state_processor.py +4 -5
- defi_services/jobs/queriers/call_state_querier.py +0 -2
- defi_services/jobs/queriers/state_querier.py +0 -3
- defi_services/services/dex/dex_info/uniswap_info.py +1 -29
- defi_services/services/dex/uniswap_v3_service.py +2 -6
- defi_services/services/lending/aave_v2_services.py +29 -44
- defi_services/services/lending/aave_v3_services.py +20 -41
- defi_services/services/lending/compound_v3_services.py +3 -7
- defi_services/services/lending/granary_services.py +4 -6
- defi_services/services/lending/justlend_service.py +3 -4
- defi_services/services/lending/lending_info/arbitrum/aave_v3_arbitrum.py +1 -1
- defi_services/services/lending/lending_info/arbitrum/compound_v3_arbitrum.py +6 -96
- defi_services/services/lending/lending_info/ethereum/aave_v3_eth.py +140 -1
- defi_services/services/lending/lending_info/ethereum/compound_v3_eth.py +5 -180
- defi_services/services/lending/lending_info/polygon/compound_v3_polygon.py +5 -35
- defi_services/services/lending/morpho_aave_v2_services.py +3 -3
- defi_services/services/lending/morpho_aave_v3_services.py +2 -2
- defi_services/services/lending/radiant_v2_services.py +10 -52
- defi_services/services/lending/trava_services.py +2 -2
- defi_services/services/lending/uwu_services.py +3 -3
- defi_services/services/lending/valas_services.py +2 -2
- defi_services/services/lending/venus_services.py +3 -9
- defi_services/services/multicall/multicall_v2.py +317 -0
- {defi_state_querier-0.5.26.dist-info → defi_state_querier-0.5.28.dist-info}/METADATA +3 -2
- {defi_state_querier-0.5.26.dist-info → defi_state_querier-0.5.28.dist-info}/RECORD +46 -83
- {defi_state_querier-0.5.26.dist-info → defi_state_querier-0.5.28.dist-info}/WHEEL +1 -1
- defi_services/abis/lending/ionic/__init__.py +0 -0
- defi_services/abis/lending/ionic/ionic_ctoken_abi.py +0 -1108
- defi_services/abis/lending/moonwell/__init__.py +0 -0
- defi_services/abis/lending/moonwell/moonwell_comptroller_abi.py +0 -1500
- defi_services/abis/lending/moonwell/moonwell_ctoken_abi.py +0 -1431
- defi_services/abis/lending/radiant_v2/radiant_reward_converter.py +0 -817
- defi_services/abis/token/trc20_abi.py +0 -304
- defi_services/abis/vault/tcv_abi.py +0 -1523
- defi_services/jobs/tcv.py +0 -144
- defi_services/services/lending/ionic_service.py +0 -167
- defi_services/services/lending/lending_info/arbitrum/venus_arbitrum.py +0 -10
- defi_services/services/lending/lending_info/base/__init__.py +0 -0
- defi_services/services/lending/lending_info/base/aave_v3_base.py +0 -61
- defi_services/services/lending/lending_info/base/compound_v3_base.py +0 -116
- defi_services/services/lending/lending_info/base/granary_base.py +0 -62
- defi_services/services/lending/lending_info/base/ionic_base.py +0 -173
- defi_services/services/lending/lending_info/base/moonwell_base.py +0 -89
- defi_services/services/lending/lending_info/base/radiant_v2_base.py +0 -57
- defi_services/services/lending/lending_info/base/sonne_base.py +0 -53
- defi_services/services/lending/lending_info/base/zerolend_base.py +0 -109
- defi_services/services/lending/lending_info/bsc/aave_v3_bsc.py +0 -68
- defi_services/services/lending/lending_info/ethereum/old_aave_v3_eth.py +0 -150
- defi_services/services/lending/lending_info/ethereum/radiant_eth.py +0 -69
- defi_services/services/lending/lending_info/ethereum/venus_eth.py +0 -10
- defi_services/services/lending/lending_info/ethereum/zerolend_eth.py +0 -96
- defi_services/services/lending/lending_info/optimism/compound_v3_optimism.py +0 -116
- defi_services/services/lending/lending_info/optimism/moonwell_optimism.py +0 -9
- defi_services/services/lending/lending_info/zksync/__init__.py +0 -0
- defi_services/services/lending/lending_info/zksync/aave_v3_zksync.py +0 -47
- defi_services/services/lending/lending_info/zksync/venus_zksync.py +0 -10
- defi_services/services/lending/lending_info/zksync/zerolend_zksync.py +0 -138
- defi_services/services/lending/moonwell_service.py +0 -120
- defi_services/services/lending/sonne_service.py +0 -64
- defi_services/services/lending/zerolend_services.py +0 -36
- defi_services/services/vault/tcv_vault_services.py +0 -108
- defi_services/services/vault/vault_info/arbitrum/__init__.py +0 -0
- defi_services/services/vault/vault_info/arbitrum/tcv_arb.py +0 -58
- /defi_services/abis/lending/{aave_v2_and_forks → aave_v2_and_forlks}/__init__.py +0 -0
- /defi_services/abis/lending/{aave_v2_and_forks → aave_v2_and_forlks}/aave_v2_event_abi.py +0 -0
- /defi_services/abis/lending/{aave_v2_and_forks → aave_v2_and_forlks}/aave_v2_incentives_abi.py +0 -0
- /defi_services/abis/lending/{aave_v2_and_forks → aave_v2_and_forlks}/lending_pool_abi.py +0 -0
- /defi_services/abis/lending/{aave_v2_and_forks → aave_v2_and_forlks}/oracle_abi.py +0 -0
- /defi_services/abis/lending/{aave_v2_and_forks → aave_v2_and_forlks}/staked_incentives_abi.py +0 -0
- /defi_services/abis/lending/{aave_v2_and_forks → aave_v2_and_forlks}/uwu_incentives_abi.py +0 -0
- {defi_state_querier-0.5.26.dist-info → defi_state_querier-0.5.28.dist-info/licenses}/LICENSE +0 -0
- {defi_state_querier-0.5.26.dist-info → defi_state_querier-0.5.28.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,17 @@
|
|
1
|
+
import csv
|
2
|
+
import json
|
3
|
+
import time
|
1
4
|
from collections import defaultdict
|
2
5
|
from typing import Tuple, List, Union, Any, Optional, Dict
|
3
6
|
|
4
7
|
from query_state_lib.base.utils.decoder import decode_eth_call_data
|
8
|
+
from query_state_lib.client.client_querier import ClientQuerier
|
5
9
|
from web3 import Web3, contract
|
6
10
|
|
11
|
+
from defi_services.abis.dex.pancakeswap.pancakeswap_lp_token_abi import LP_TOKEN_ABI
|
7
12
|
from defi_services.abis.multicall_v3_abi import MULTICALL_V3_ABI
|
13
|
+
from defi_services.abis.token.erc20_abi import ERC20_ABI
|
14
|
+
from defi_services.constants.network_constants import MulticallContract, Chains, Networks
|
8
15
|
from defi_services.services.multicall.batch_queries_service import add_rpc_call, decode_data_response, \
|
9
16
|
decode_data_response_ignore_error
|
10
17
|
from defi_services.utils.dict_utils import all_equal
|
@@ -177,3 +184,313 @@ def decode_multical_response(w3_multicall: W3Multicall, data_responses, list_cal
|
|
177
184
|
batch_idx += 1
|
178
185
|
|
179
186
|
return results
|
187
|
+
|
188
|
+
|
189
|
+
def _test_multicall(_w3: Web3, multicall_contract, wallets, tokens):
|
190
|
+
start_time = time.time()
|
191
|
+
encode_time = 0
|
192
|
+
|
193
|
+
rpc_call_id = {}
|
194
|
+
|
195
|
+
n_calls = 0
|
196
|
+
data = {}
|
197
|
+
for wallet in wallets:
|
198
|
+
start_encode_time = time.time()
|
199
|
+
data[wallet] = {}
|
200
|
+
|
201
|
+
w3_multicall = W3Multicall(_w3, address=MulticallContract.get_multicall_contract(Chains.arbitrum))
|
202
|
+
for token in tokens:
|
203
|
+
# if token['address'] == '0x0000000000000000000000000000000000000000':
|
204
|
+
# continue
|
205
|
+
|
206
|
+
w3_multicall.add(W3Multicall.Call(
|
207
|
+
Web3.to_checksum_address(token['address']), # contract address
|
208
|
+
ERC20_ABI, # method signature to call
|
209
|
+
'balanceOf',
|
210
|
+
wallet
|
211
|
+
))
|
212
|
+
|
213
|
+
decimals_call = W3Multicall.Call(
|
214
|
+
Web3.to_checksum_address(token['address']), # contract address
|
215
|
+
ERC20_ABI, # method signature to call
|
216
|
+
'decimals'
|
217
|
+
)
|
218
|
+
if decimals_call not in rpc_call_id:
|
219
|
+
w3_multicall.add(decimals_call)
|
220
|
+
rpc_call_id[decimals_call] = None
|
221
|
+
|
222
|
+
encode_time += time.time() - start_encode_time
|
223
|
+
n_calls += len(w3_multicall.calls)
|
224
|
+
|
225
|
+
# For single call
|
226
|
+
inputs = w3_multicall.get_params()
|
227
|
+
response = multicall_contract.functions.tryAggregate(*inputs).call()
|
228
|
+
results = w3_multicall.decode(response)
|
229
|
+
|
230
|
+
for token in tokens:
|
231
|
+
# if token['address'] == '0x0000000000000000000000000000000000000000':
|
232
|
+
# continue
|
233
|
+
|
234
|
+
decimals_call_id = f'decimals_{token["address"]}_latest'.lower()
|
235
|
+
balance_call_id = f'balanceOf_{token["address"]}_{wallet}_latest'.lower()
|
236
|
+
|
237
|
+
decimals = results.get(decimals_call_id)
|
238
|
+
if decimals is None:
|
239
|
+
decimals = rpc_call_id.get(decimals_call_id) or 18
|
240
|
+
else:
|
241
|
+
rpc_call_id[decimals_call_id] = decimals
|
242
|
+
|
243
|
+
balance = results.get(balance_call_id)
|
244
|
+
if balance is None:
|
245
|
+
balance = rpc_call_id.get(balance_call_id) or 0
|
246
|
+
else:
|
247
|
+
rpc_call_id[balance_call_id] = balance
|
248
|
+
balance /= 10 ** decimals
|
249
|
+
|
250
|
+
data[wallet][token['address']] = {
|
251
|
+
'name': token['name'],
|
252
|
+
'symbol': token['symbol'],
|
253
|
+
'balance': balance,
|
254
|
+
'decimals': decimals
|
255
|
+
}
|
256
|
+
|
257
|
+
with open('results_multicall.json', 'w') as f:
|
258
|
+
json.dump(data, f, indent=2)
|
259
|
+
duration = time.time() - start_time
|
260
|
+
|
261
|
+
print(f'There are {n_calls} calls')
|
262
|
+
print(f'Encode took {round(encode_time, 3)}s')
|
263
|
+
print(f'Done after {round(duration, 3)}s')
|
264
|
+
|
265
|
+
return duration, encode_time, n_calls
|
266
|
+
|
267
|
+
|
268
|
+
def _test_state_querier(client_querier: ClientQuerier, wallets, tokens):
|
269
|
+
start_time = time.time()
|
270
|
+
|
271
|
+
list_call_id = []
|
272
|
+
list_rpc_call = []
|
273
|
+
|
274
|
+
for wallet in wallets:
|
275
|
+
for token in tokens:
|
276
|
+
if token['address'] == '0x0000000000000000000000000000000000000000':
|
277
|
+
continue
|
278
|
+
|
279
|
+
add_rpc_call(
|
280
|
+
abi=ERC20_ABI, contract_address=Web3.to_checksum_address(token['address']),
|
281
|
+
fn_name="balanceOf", fn_paras=wallet, block_number='latest',
|
282
|
+
list_call_id=list_call_id, list_rpc_call=list_rpc_call
|
283
|
+
)
|
284
|
+
add_rpc_call(
|
285
|
+
abi=ERC20_ABI, contract_address=Web3.to_checksum_address(token['address']),
|
286
|
+
fn_name="decimals", block_number='latest',
|
287
|
+
list_call_id=list_call_id, list_rpc_call=list_rpc_call
|
288
|
+
)
|
289
|
+
|
290
|
+
encode_time = time.time() - start_time
|
291
|
+
print(f'There are {len(list_rpc_call)} calls')
|
292
|
+
print(f'Encode took {round(encode_time, 3)}s')
|
293
|
+
|
294
|
+
responses = client_querier.sent_batch_to_provider(list_rpc_call, batch_size=2000)
|
295
|
+
decoded_data = decode_data_response_ignore_error(data_responses=responses, list_call_id=list_call_id)
|
296
|
+
|
297
|
+
data = {}
|
298
|
+
for wallet in wallets:
|
299
|
+
data[wallet] = {}
|
300
|
+
for token in tokens:
|
301
|
+
if token['address'] == '0x0000000000000000000000000000000000000000':
|
302
|
+
continue
|
303
|
+
|
304
|
+
decimals = decoded_data.get(f'decimals_{token["address"]}_latest'.lower())
|
305
|
+
balance = decoded_data.get(f'balanceOf_{token["address"]}_{wallet}_latest'.lower()) / 10 ** decimals
|
306
|
+
|
307
|
+
data[wallet][token['address']] = {
|
308
|
+
'name': token['name'],
|
309
|
+
'symbol': token['symbol'],
|
310
|
+
'balance': balance,
|
311
|
+
'decimals': decimals
|
312
|
+
}
|
313
|
+
|
314
|
+
with open('results_querier.json', 'w') as f:
|
315
|
+
json.dump(data, f, indent=2)
|
316
|
+
duration = time.time() - start_time
|
317
|
+
print(f'Done after {round(duration, 3)}s')
|
318
|
+
|
319
|
+
return duration, encode_time, len(list_rpc_call)
|
320
|
+
|
321
|
+
|
322
|
+
def _test_multicall_with_multiprocessing(_w3: Web3, client_querier: ClientQuerier, wallets, tokens):
|
323
|
+
start_time = time.time()
|
324
|
+
|
325
|
+
w3_multicall = W3Multicall(_w3, address=MulticallContract.get_multicall_contract(Chains.arbitrum))
|
326
|
+
for wallet in wallets:
|
327
|
+
for token in tokens:
|
328
|
+
# if token['address'] == '0x0000000000000000000000000000000000000000':
|
329
|
+
# continue
|
330
|
+
|
331
|
+
w3_multicall.add(W3Multicall.Call(
|
332
|
+
Web3.to_checksum_address(token['address']), # contract address
|
333
|
+
ERC20_ABI, # method signature to call
|
334
|
+
'balanceOf',
|
335
|
+
wallet
|
336
|
+
))
|
337
|
+
|
338
|
+
w3_multicall.add(W3Multicall.Call(
|
339
|
+
Web3.to_checksum_address(token['address']), # contract address
|
340
|
+
ERC20_ABI, # method signature to call
|
341
|
+
'decimals'
|
342
|
+
))
|
343
|
+
|
344
|
+
w3_multicall.add(W3Multicall.Call(
|
345
|
+
Web3.to_checksum_address(token['address']), # contract address
|
346
|
+
LP_TOKEN_ABI, # method signature to call
|
347
|
+
'token0'
|
348
|
+
))
|
349
|
+
|
350
|
+
list_call_id, list_rpc_call = [], []
|
351
|
+
add_rpc_multicall(w3_multicall, list_rpc_call=list_rpc_call, list_call_id=list_call_id)
|
352
|
+
|
353
|
+
encode_time = time.time() - start_time
|
354
|
+
|
355
|
+
responses = client_querier.sent_batch_to_provider(list_rpc_call, batch_size=1)
|
356
|
+
decoded_data = decode_multical_response(
|
357
|
+
w3_multicall=w3_multicall, data_responses=responses,
|
358
|
+
list_call_id=list_call_id, ignore_error=True
|
359
|
+
)
|
360
|
+
|
361
|
+
data = {}
|
362
|
+
for wallet in wallets:
|
363
|
+
data[wallet] = {}
|
364
|
+
for token in tokens:
|
365
|
+
# if token['address'] == '0x0000000000000000000000000000000000000000':
|
366
|
+
# continue
|
367
|
+
|
368
|
+
decimals_call_id = f'decimals_{token["address"]}_latest'.lower()
|
369
|
+
balance_call_id = f'balanceOf_{token["address"]}_{wallet}_latest'.lower()
|
370
|
+
|
371
|
+
decimals = decoded_data.get(decimals_call_id) or 18
|
372
|
+
balance = decoded_data.get(balance_call_id, 0) / 10 ** decimals
|
373
|
+
|
374
|
+
data[wallet][token['address']] = {
|
375
|
+
'name': token['name'],
|
376
|
+
'symbol': token['symbol'],
|
377
|
+
'balance': balance,
|
378
|
+
'decimals': decimals
|
379
|
+
}
|
380
|
+
|
381
|
+
with open('results_multicall_with_multiprocessing.json', 'w') as f:
|
382
|
+
json.dump(data, f, indent=2)
|
383
|
+
duration = time.time() - start_time
|
384
|
+
|
385
|
+
print(f'There are {len(w3_multicall.calls)} calls')
|
386
|
+
print(f'Encode took {round(encode_time, 3)}s')
|
387
|
+
print(f'Done after {round(duration, 3)}s')
|
388
|
+
|
389
|
+
return duration, encode_time, len(w3_multicall.calls)
|
390
|
+
|
391
|
+
|
392
|
+
def query_multi_contracts(n_times=20, wallets_batch_size=5, wallets_distribute_similar=True):
|
393
|
+
with open('../../../.data/wallets.json') as f:
|
394
|
+
wallets = json.load(f)
|
395
|
+
wallets = ['0x6FfA563915CB3186b9Dd206D0E08bdeDcd2EA2ED']
|
396
|
+
|
397
|
+
with open('../../../.data/tokens.json') as f:
|
398
|
+
tokens_ = json.load(f)
|
399
|
+
tokens_ = [
|
400
|
+
{
|
401
|
+
"address": "0xE2035f04040A135c4dA2f96AcA742143c57c79F9",
|
402
|
+
"name": "UXUY",
|
403
|
+
"symbol": "uxuy"
|
404
|
+
},
|
405
|
+
{
|
406
|
+
"address": "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9",
|
407
|
+
"name": "Tether",
|
408
|
+
"symbol": "usdt"
|
409
|
+
},
|
410
|
+
{
|
411
|
+
"address": "0x0000000000000000000000000000000000000000",
|
412
|
+
"name": "ETH",
|
413
|
+
"symbol": "ETH"
|
414
|
+
}
|
415
|
+
]
|
416
|
+
|
417
|
+
print(f'There are maximum {len(wallets)} wallets')
|
418
|
+
print(f'There are {len(tokens_)} tokens')
|
419
|
+
|
420
|
+
if wallets_distribute_similar:
|
421
|
+
wallets_batch = [wallets[:300], wallets[:300], wallets[:300]]
|
422
|
+
else:
|
423
|
+
wallets_batch = [wallets[:300], wallets[300:600], wallets[600:900]]
|
424
|
+
|
425
|
+
# Methodology 1: Query State Lib
|
426
|
+
start_time = time.time()
|
427
|
+
client_querier = ClientQuerier(provider_url=Networks.providers['arbitrum'])
|
428
|
+
starting_time_1 = time.time() - start_time
|
429
|
+
logger.info(f'Starting state querier: {round(starting_time_1, 3)}s')
|
430
|
+
|
431
|
+
_multiple(
|
432
|
+
n_times=n_times, starting_time=starting_time_1, filename='query_state_lib',
|
433
|
+
wallets=wallets_batch[0], wallets_batch_size=wallets_batch_size, tokens=tokens_, func=_test_state_querier,
|
434
|
+
client_querier=client_querier
|
435
|
+
)
|
436
|
+
|
437
|
+
# Methodology 2: Multicall
|
438
|
+
start_time = time.time()
|
439
|
+
_w3 = Web3(Web3.HTTPProvider(Networks.providers['arbitrum']))
|
440
|
+
starting_time_2_1 = time.time() - start_time
|
441
|
+
multicall_address = MulticallContract.get_multicall_contract(Chains.arbitrum)
|
442
|
+
multicall_contract = _w3.eth.contract(Web3.to_checksum_address(multicall_address), abi=MULTICALL_V3_ABI)
|
443
|
+
starting_time_2 = time.time() - start_time
|
444
|
+
logger.info(f'Starting multicall: {round(starting_time_2, 3)}s')
|
445
|
+
|
446
|
+
_multiple(
|
447
|
+
n_times=n_times, starting_time=starting_time_2, filename='multicall',
|
448
|
+
wallets=wallets_batch[1], wallets_batch_size=wallets_batch_size, tokens=tokens_, func=_test_multicall,
|
449
|
+
_w3=_w3, multicall_contract=multicall_contract
|
450
|
+
)
|
451
|
+
|
452
|
+
# Methodology 3: Combine Multicall with multiprocessing
|
453
|
+
starting_time_3 = starting_time_1 + starting_time_2_1
|
454
|
+
logger.info(f'Starting combined: {round(starting_time_3, 3)}s')
|
455
|
+
|
456
|
+
_multiple(
|
457
|
+
n_times=n_times, starting_time=starting_time_3, filename='combined',
|
458
|
+
wallets=wallets_batch[2], wallets_batch_size=wallets_batch_size, tokens=tokens_,
|
459
|
+
func=_test_multicall_with_multiprocessing, _w3=_w3, client_querier=client_querier
|
460
|
+
)
|
461
|
+
|
462
|
+
|
463
|
+
def _multiple(n_times, starting_time, filename, wallets, wallets_batch_size, tokens, func, *args, **kwargs):
|
464
|
+
data = [['Total Time', 'Encode Time']]
|
465
|
+
overview = {
|
466
|
+
'avg_total_time': 0, 'avg_encode_time': 0,
|
467
|
+
'times': 0, 'errors': 0,
|
468
|
+
'queries': 0, 'start_time': starting_time
|
469
|
+
}
|
470
|
+
for i in range(n_times):
|
471
|
+
idx = i * wallets_batch_size
|
472
|
+
sub_wallets = wallets[idx:idx + wallets_batch_size]
|
473
|
+
try:
|
474
|
+
total_time, encode_time, n_calls = func(wallets=sub_wallets, tokens=tokens, *args, **kwargs)
|
475
|
+
|
476
|
+
overview['queries'] = n_calls
|
477
|
+
data.append([total_time, encode_time])
|
478
|
+
overview['times'] += 1
|
479
|
+
except Exception as ex:
|
480
|
+
logger.exception(ex)
|
481
|
+
overview['errors'] += 1
|
482
|
+
finally:
|
483
|
+
time.sleep(13)
|
484
|
+
|
485
|
+
with open(f'results_{filename}.csv', 'w') as f:
|
486
|
+
writer = csv.writer(f)
|
487
|
+
writer.writerows(data)
|
488
|
+
|
489
|
+
overview['avg_total_time'] = sum([t[0] for t in data[1:]]) / overview['times']
|
490
|
+
overview['avg_encode_time'] = sum([t[1] for t in data[1:]]) / overview['times']
|
491
|
+
with open(f'overview_results_{filename}.json', 'w') as f:
|
492
|
+
json.dump(overview, f, indent=2)
|
493
|
+
|
494
|
+
|
495
|
+
if __name__ == '__main__':
|
496
|
+
query_multi_contracts(n_times=1, wallets_batch_size=1, wallets_distribute_similar=True)
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: defi-state-querier
|
3
|
-
Version: 0.5.
|
3
|
+
Version: 0.5.28
|
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
|
@@ -23,6 +23,7 @@ Dynamic: classifier
|
|
23
23
|
Dynamic: description
|
24
24
|
Dynamic: description-content-type
|
25
25
|
Dynamic: home-page
|
26
|
+
Dynamic: license-file
|
26
27
|
Dynamic: project-url
|
27
28
|
Dynamic: requires-dist
|
28
29
|
Dynamic: requires-python
|