defi-state-querier 0.4.30__py3-none-any.whl → 0.5.0__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/abis/multicall_v3_abi.py +440 -0
 - defi_services/constants/network_constants.py +387 -0
 - defi_services/jobs/processors/multicall_state_processor.py +15 -0
 - defi_services/jobs/queriers/multicall_state_querier.py +101 -0
 - defi_services/services/eth/__init__.py +0 -0
 - defi_services/services/eth/eth_services.py +91 -0
 - defi_services/services/multicall/__init__.py +0 -0
 - defi_services/services/multicall/batch_queries_service.py +102 -0
 - defi_services/services/multicall/multicall_v2.py +492 -0
 - defi_services/services/multicall/state_query_service.py +549 -0
 - defi_services/services/token_services.py +4 -3
 - defi_services/utils/dict_utils.py +95 -0
 - {defi_state_querier-0.4.30.dist-info → defi_state_querier-0.5.0.dist-info}/METADATA +1 -1
 - {defi_state_querier-0.4.30.dist-info → defi_state_querier-0.5.0.dist-info}/RECORD +18 -7
 - {defi_state_querier-0.4.30.dist-info → defi_state_querier-0.5.0.dist-info}/LICENSE +0 -0
 - {defi_state_querier-0.4.30.dist-info → defi_state_querier-0.5.0.dist-info}/WHEEL +0 -0
 - {defi_state_querier-0.4.30.dist-info → defi_state_querier-0.5.0.dist-info}/top_level.txt +0 -0
 
| 
         @@ -0,0 +1,387 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import os
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            import dotenv
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            dotenv.load_dotenv()
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            POLYGON_AAVE_ADDRESS = '0x8dff5e27ea6b7ac08ebfdf9eb090f32ee9a30fcf'
         
     | 
| 
      
 8 
     | 
    
         
            +
            ETHEREUM_AAVE_ADDRESS = '0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            BSC_TRAVA_ADDRESS = '0x75de5f7c91a89c16714017c7443eca20c7a8c295'
         
     | 
| 
      
 11 
     | 
    
         
            +
            ETH_TRAVA_ADDRESS = '0xd61afaaa8a69ba541bc4db9c9b40d4142b43b9a4'
         
     | 
| 
      
 12 
     | 
    
         
            +
            FTM_TRAVA_ADDRESS = '0xd98bb590bdfabf18c164056c185fbb6be5ee643f'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            BSC_VALAS_ADDRESS = '0xe29a55a6aeff5c8b1beede5bcf2f0cb3af8f91f5'
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            BSC_VENUS_ADDRESS = '0xfd36e2c2a6789db23113685031d7f16329158384'
         
     | 
| 
      
 17 
     | 
    
         
            +
            BSC_CREAM_ADDRESS = '0x589de0f0ccf905477646599bb3e5c622c84cc0ba'
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            FTM_GEIST_ADDRESS = '0x9fad24f572045c7869117160a571b2e50b10d068'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            ETH_COMPOUND_ADDRESS = '0x3d9819210a31b4961b30ef54be2aed79b9c9cd3b'
         
     | 
| 
      
 22 
     | 
    
         
            +
            ETH_CREAM_ADDRESS = ''
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            class Chains:
         
     | 
| 
      
 26 
     | 
    
         
            +
                bsc = '0x38'
         
     | 
| 
      
 27 
     | 
    
         
            +
                ethereum = '0x1'
         
     | 
| 
      
 28 
     | 
    
         
            +
                fantom = '0xfa'
         
     | 
| 
      
 29 
     | 
    
         
            +
                polygon = '0x89'
         
     | 
| 
      
 30 
     | 
    
         
            +
                arbitrum = '0xa4b1'
         
     | 
| 
      
 31 
     | 
    
         
            +
                optimism = '0xa'
         
     | 
| 
      
 32 
     | 
    
         
            +
                avalanche = '0xa86a'
         
     | 
| 
      
 33 
     | 
    
         
            +
                tron = '0x2b6653dc'
         
     | 
| 
      
 34 
     | 
    
         
            +
                cronos = '0x19'
         
     | 
| 
      
 35 
     | 
    
         
            +
                solana = 'solana'
         
     | 
| 
      
 36 
     | 
    
         
            +
                polkadot = 'polkadot'
         
     | 
| 
      
 37 
     | 
    
         
            +
                bitcoin = 'bitcoin'
         
     | 
| 
      
 38 
     | 
    
         
            +
                cosmos = 'cosmos'
         
     | 
| 
      
 39 
     | 
    
         
            +
                base = '0x2105'
         
     | 
| 
      
 40 
     | 
    
         
            +
                kava = '0x8ae'
         
     | 
| 
      
 41 
     | 
    
         
            +
                gnosis = '0x64'
         
     | 
| 
      
 42 
     | 
    
         
            +
                klaytn = '0x2019'
         
     | 
| 
      
 43 
     | 
    
         
            +
                mantle = '0x1388'
         
     | 
| 
      
 44 
     | 
    
         
            +
                celo = '0xa4ec'
         
     | 
| 
      
 45 
     | 
    
         
            +
                moonbeam = '0x504'
         
     | 
| 
      
 46 
     | 
    
         
            +
                manta = '0xa9'
         
     | 
| 
      
 47 
     | 
    
         
            +
                pulse = '0x171'
         
     | 
| 
      
 48 
     | 
    
         
            +
                rootstock = '0x1e'
         
     | 
| 
      
 49 
     | 
    
         
            +
                astar = '0x250'
         
     | 
| 
      
 50 
     | 
    
         
            +
                metis = '0x440'
         
     | 
| 
      
 51 
     | 
    
         
            +
                canto = '0x1e14'
         
     | 
| 
      
 52 
     | 
    
         
            +
                heco = '0x80'
         
     | 
| 
      
 53 
     | 
    
         
            +
                linea = '0xe708'
         
     | 
| 
      
 54 
     | 
    
         
            +
                okc = '0x42'
         
     | 
| 
      
 55 
     | 
    
         
            +
                aurora = '0x4e454152'
         
     | 
| 
      
 56 
     | 
    
         
            +
                moonriver = '0x505'
         
     | 
| 
      
 57 
     | 
    
         
            +
                oasis_sapphire = '0x5afe'
         
     | 
| 
      
 58 
     | 
    
         
            +
                oasis_sapphire_testnet = '0x5aff'
         
     | 
| 
      
 59 
     | 
    
         
            +
                blast = '0xee'
         
     | 
| 
      
 60 
     | 
    
         
            +
                oraichain = 'orai'
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                none_wrapped_token = [arbitrum, fantom, optimism]
         
     | 
| 
      
 63 
     | 
    
         
            +
                all = [
         
     | 
| 
      
 64 
     | 
    
         
            +
                    bsc, ethereum, fantom, polygon, arbitrum, optimism,
         
     | 
| 
      
 65 
     | 
    
         
            +
                    avalanche, tron, cronos, solana, polkadot, bitcoin, cosmos,
         
     | 
| 
      
 66 
     | 
    
         
            +
                    oraichain
         
     | 
| 
      
 67 
     | 
    
         
            +
                ]
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                mapping = {
         
     | 
| 
      
 70 
     | 
    
         
            +
                    'bsc': bsc,
         
     | 
| 
      
 71 
     | 
    
         
            +
                    'ethereum': ethereum,
         
     | 
| 
      
 72 
     | 
    
         
            +
                    'fantom': fantom,
         
     | 
| 
      
 73 
     | 
    
         
            +
                    'polygon': polygon,
         
     | 
| 
      
 74 
     | 
    
         
            +
                    'arbitrum': arbitrum,
         
     | 
| 
      
 75 
     | 
    
         
            +
                    'optimism': optimism,
         
     | 
| 
      
 76 
     | 
    
         
            +
                    'avalanche': avalanche,
         
     | 
| 
      
 77 
     | 
    
         
            +
                    'tron': tron,
         
     | 
| 
      
 78 
     | 
    
         
            +
                    'cronos': cronos,
         
     | 
| 
      
 79 
     | 
    
         
            +
                    'solana': solana,
         
     | 
| 
      
 80 
     | 
    
         
            +
                    'polkadot': polkadot,
         
     | 
| 
      
 81 
     | 
    
         
            +
                    'oasis_sapphire': oasis_sapphire,
         
     | 
| 
      
 82 
     | 
    
         
            +
                    'oasis_sapphire_testnet': oasis_sapphire_testnet
         
     | 
| 
      
 83 
     | 
    
         
            +
                }
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                names = {
         
     | 
| 
      
 86 
     | 
    
         
            +
                    bsc: 'bsc',
         
     | 
| 
      
 87 
     | 
    
         
            +
                    ethereum: "ethereum",
         
     | 
| 
      
 88 
     | 
    
         
            +
                    fantom: 'fantom',
         
     | 
| 
      
 89 
     | 
    
         
            +
                    polygon: 'polygon',
         
     | 
| 
      
 90 
     | 
    
         
            +
                    arbitrum: 'arbitrum',
         
     | 
| 
      
 91 
     | 
    
         
            +
                    optimism: 'optimism',
         
     | 
| 
      
 92 
     | 
    
         
            +
                    avalanche: 'avalanche',
         
     | 
| 
      
 93 
     | 
    
         
            +
                    tron: 'tron',
         
     | 
| 
      
 94 
     | 
    
         
            +
                    cronos: 'cronos',
         
     | 
| 
      
 95 
     | 
    
         
            +
                    solana: 'solana',
         
     | 
| 
      
 96 
     | 
    
         
            +
                    polkadot: 'polkadot',
         
     | 
| 
      
 97 
     | 
    
         
            +
                    oasis_sapphire: 'oasis_sapphire',
         
     | 
| 
      
 98 
     | 
    
         
            +
                    oasis_sapphire_testnet: 'oasis_sapphire_testnet'
         
     | 
| 
      
 99 
     | 
    
         
            +
                }
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                abi_mapping = {
         
     | 
| 
      
 102 
     | 
    
         
            +
                    bsc: 'bep20_abi',
         
     | 
| 
      
 103 
     | 
    
         
            +
                    ethereum: 'erc20_abi',
         
     | 
| 
      
 104 
     | 
    
         
            +
                    fantom: 'erc20_abi',
         
     | 
| 
      
 105 
     | 
    
         
            +
                    polygon: 'erc20_abi',
         
     | 
| 
      
 106 
     | 
    
         
            +
                    arbitrum: 'erc20_abi',
         
     | 
| 
      
 107 
     | 
    
         
            +
                    optimism: 'erc20_abi',
         
     | 
| 
      
 108 
     | 
    
         
            +
                    avalanche: 'erc20_abi',
         
     | 
| 
      
 109 
     | 
    
         
            +
                    tron: 'trc20_abi',
         
     | 
| 
      
 110 
     | 
    
         
            +
                    cronos: 'crc20_abi'
         
     | 
| 
      
 111 
     | 
    
         
            +
                }
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                block_time = {
         
     | 
| 
      
 114 
     | 
    
         
            +
                    bsc: 3,
         
     | 
| 
      
 115 
     | 
    
         
            +
                    ethereum: 12,
         
     | 
| 
      
 116 
     | 
    
         
            +
                    fantom: 1,
         
     | 
| 
      
 117 
     | 
    
         
            +
                    polygon: 2,
         
     | 
| 
      
 118 
     | 
    
         
            +
                    arbitrum: 0.3,
         
     | 
| 
      
 119 
     | 
    
         
            +
                    avalanche: 2
         
     | 
| 
      
 120 
     | 
    
         
            +
                }
         
     | 
| 
      
 121 
     | 
    
         
            +
                wrapped_native_token = {
         
     | 
| 
      
 122 
     | 
    
         
            +
                    bsc: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
         
     | 
| 
      
 123 
     | 
    
         
            +
                    ethereum: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
         
     | 
| 
      
 124 
     | 
    
         
            +
                    polygon: "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270",
         
     | 
| 
      
 125 
     | 
    
         
            +
                    fantom: "0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83",
         
     | 
| 
      
 126 
     | 
    
         
            +
                    arbitrum: "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
         
     | 
| 
      
 127 
     | 
    
         
            +
                    optimism: "0x4200000000000000000000000000000000000006",
         
     | 
| 
      
 128 
     | 
    
         
            +
                    avalanche: "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7",
         
     | 
| 
      
 129 
     | 
    
         
            +
                    tron: "0x891cdb91d149f23b1a45d9c5ca78a88d0cb44c18",
         
     | 
| 
      
 130 
     | 
    
         
            +
                    cronos: "0x5c7f8a570d578ed84e63fdfa7b1ee72deae1ae23"
         
     | 
| 
      
 131 
     | 
    
         
            +
                }
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                evm = {
         
     | 
| 
      
 134 
     | 
    
         
            +
                    ethereum: True, bsc: True, polygon: True, fantom: True,
         
     | 
| 
      
 135 
     | 
    
         
            +
                    arbitrum: True, optimism: True, avalanche: True, tron: True, cronos: True,
         
     | 
| 
      
 136 
     | 
    
         
            +
                    base: True, kava: True, gnosis: True, klaytn: True, mantle: True, celo: True, moonbeam: True, manta: True,
         
     | 
| 
      
 137 
     | 
    
         
            +
                    pulse: True, rootstock: True, astar: True, metis: True, canto: True, heco: True, linea: True, okc: True,
         
     | 
| 
      
 138 
     | 
    
         
            +
                    aurora: True, moonriver: True, oasis_sapphire: True, blast: True
         
     | 
| 
      
 139 
     | 
    
         
            +
                }
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                def get_abi_name(self, chain_id):
         
     | 
| 
      
 142 
     | 
    
         
            +
                    """Map chain_id with the corresponding abi key
         
     | 
| 
      
 143 
     | 
    
         
            +
                    e.g.: '0x38' -> 'bep20_abi' or '0x1' -> 'erc20_abi'
         
     | 
| 
      
 144 
     | 
    
         
            +
                    """
         
     | 
| 
      
 145 
     | 
    
         
            +
                    return self.abi_mapping.get(chain_id, '')
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
            class ChainsAnkr:
         
     | 
| 
      
 149 
     | 
    
         
            +
                """Chain name for Ankr API"""
         
     | 
| 
      
 150 
     | 
    
         
            +
                bsc = '0x38'
         
     | 
| 
      
 151 
     | 
    
         
            +
                eth = '0x1'
         
     | 
| 
      
 152 
     | 
    
         
            +
                fantom = '0xfa'
         
     | 
| 
      
 153 
     | 
    
         
            +
                polygon = '0x89'
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                reversed_mapping = {
         
     | 
| 
      
 156 
     | 
    
         
            +
                    bsc: 'bsc',
         
     | 
| 
      
 157 
     | 
    
         
            +
                    eth: 'eth',
         
     | 
| 
      
 158 
     | 
    
         
            +
                    fantom: 'fantom',
         
     | 
| 
      
 159 
     | 
    
         
            +
                    polygon: 'polygon',
         
     | 
| 
      
 160 
     | 
    
         
            +
                }
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                def get_chain_name(self, chain_id):
         
     | 
| 
      
 163 
     | 
    
         
            +
                    return self.reversed_mapping.get(chain_id)
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
            class Scans:
         
     | 
| 
      
 167 
     | 
    
         
            +
                mapping = {
         
     | 
| 
      
 168 
     | 
    
         
            +
                    'bscscan': Chains.bsc,
         
     | 
| 
      
 169 
     | 
    
         
            +
                    'etherscan': Chains.ethereum,
         
     | 
| 
      
 170 
     | 
    
         
            +
                    'ftmscan': Chains.fantom,
         
     | 
| 
      
 171 
     | 
    
         
            +
                    'polygonscan': Chains.polygon,
         
     | 
| 
      
 172 
     | 
    
         
            +
                    'arbiscan': Chains.arbitrum,
         
     | 
| 
      
 173 
     | 
    
         
            +
                    'optimistic': Chains.optimism,
         
     | 
| 
      
 174 
     | 
    
         
            +
                    'snowtrace': Chains.avalanche,
         
     | 
| 
      
 175 
     | 
    
         
            +
                    'cronoscan': Chains.cronos
         
     | 
| 
      
 176 
     | 
    
         
            +
                }
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                api_keys = {
         
     | 
| 
      
 179 
     | 
    
         
            +
                    Chains.bsc: 'GKRVTEQHSGWX335P21994DKNSTJVDYYXJ1',
         
     | 
| 
      
 180 
     | 
    
         
            +
                    Chains.ethereum: 'YQVXQAJAYNS7AC48ZXS1NT45RKYRPY7P7E',
         
     | 
| 
      
 181 
     | 
    
         
            +
                    Chains.fantom: 'Y85XY5DDDN4Z7C7Z4ZX8N62M5WET7D8NYC',
         
     | 
| 
      
 182 
     | 
    
         
            +
                    Chains.polygon: 'EYADI5Q4VK4VF99KFEJURMVE9CNE54YEYW',
         
     | 
| 
      
 183 
     | 
    
         
            +
                    Chains.arbitrum: 'BU5VN8872FE119RDX898MS5EZHE11FPZSC',
         
     | 
| 
      
 184 
     | 
    
         
            +
                    Chains.optimism: '1JW9PDV2HZZI3WRFQRVGWUDD2T1RV8GWX3',
         
     | 
| 
      
 185 
     | 
    
         
            +
                    Chains.avalanche: 'JWNM6Y5UA1499PWVA2T55MEH3TZDGAKJWJ',
         
     | 
| 
      
 186 
     | 
    
         
            +
                    Chains.cronos: 'F5J6423D42PM21CDP61SUD6H7DE4FXH2DE'
         
     | 
| 
      
 187 
     | 
    
         
            +
                }
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                api_bases = {
         
     | 
| 
      
 190 
     | 
    
         
            +
                    Chains.bsc: 'https://api.bscscan.com/api',
         
     | 
| 
      
 191 
     | 
    
         
            +
                    Chains.ethereum: 'https://api.etherscan.io/api',
         
     | 
| 
      
 192 
     | 
    
         
            +
                    Chains.fantom: 'https://api.ftmscan.com/api',
         
     | 
| 
      
 193 
     | 
    
         
            +
                    Chains.polygon: 'https://api.polygonscan.com/api',
         
     | 
| 
      
 194 
     | 
    
         
            +
                    Chains.arbitrum: 'https://api.arbiscan.io/api',
         
     | 
| 
      
 195 
     | 
    
         
            +
                    Chains.optimism: 'https://api-optimistic.etherscan.io/api',
         
     | 
| 
      
 196 
     | 
    
         
            +
                    Chains.avalanche: 'https://api.snowtrace.io/api',
         
     | 
| 
      
 197 
     | 
    
         
            +
                    Chains.cronos: 'https://cronoscan.com/api'
         
     | 
| 
      
 198 
     | 
    
         
            +
                }
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                scan_base_urls = {
         
     | 
| 
      
 201 
     | 
    
         
            +
                    Chains.ethereum: 'https://etherscan.io/',
         
     | 
| 
      
 202 
     | 
    
         
            +
                    Chains.bsc: 'https://bscscan.com/',
         
     | 
| 
      
 203 
     | 
    
         
            +
                    Chains.fantom: 'https://ftmscan.com/',
         
     | 
| 
      
 204 
     | 
    
         
            +
                    Chains.polygon: 'https://polygonscan.com/',
         
     | 
| 
      
 205 
     | 
    
         
            +
                    Chains.arbitrum: 'https://arbiscan.io/',
         
     | 
| 
      
 206 
     | 
    
         
            +
                    Chains.optimism: 'https://optimistic.etherscan.io/',
         
     | 
| 
      
 207 
     | 
    
         
            +
                    Chains.avalanche: 'https://snowtrace.io/',
         
     | 
| 
      
 208 
     | 
    
         
            +
                    Chains.cronos: 'https://cronoscan.com/'
         
     | 
| 
      
 209 
     | 
    
         
            +
                }
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                all_base_urls = {
         
     | 
| 
      
 212 
     | 
    
         
            +
                    Chains.bsc: [
         
     | 
| 
      
 213 
     | 
    
         
            +
                        'https://bscscan.com/token',
         
     | 
| 
      
 214 
     | 
    
         
            +
                        'https://bscscan-com.translate.goog/token'
         
     | 
| 
      
 215 
     | 
    
         
            +
                    ],
         
     | 
| 
      
 216 
     | 
    
         
            +
                    Chains.polygon: [
         
     | 
| 
      
 217 
     | 
    
         
            +
                        'https://polygonscan.com/token',
         
     | 
| 
      
 218 
     | 
    
         
            +
                        'https://polygonscan-com.translate.goog/token'
         
     | 
| 
      
 219 
     | 
    
         
            +
                    ],
         
     | 
| 
      
 220 
     | 
    
         
            +
                    Chains.ethereum: [
         
     | 
| 
      
 221 
     | 
    
         
            +
                        'https://etherscan.io/token',
         
     | 
| 
      
 222 
     | 
    
         
            +
                        'https://etherscan-io.translate.goog/token',
         
     | 
| 
      
 223 
     | 
    
         
            +
                    ],
         
     | 
| 
      
 224 
     | 
    
         
            +
                    Chains.fantom: [
         
     | 
| 
      
 225 
     | 
    
         
            +
                        'https://ftmscan.com/token',
         
     | 
| 
      
 226 
     | 
    
         
            +
                        'https://ftmscan-com.translate.goog/token'
         
     | 
| 
      
 227 
     | 
    
         
            +
                    ],
         
     | 
| 
      
 228 
     | 
    
         
            +
                    Chains.arbitrum: [
         
     | 
| 
      
 229 
     | 
    
         
            +
                        # 'https://arbiscan-io.translate.goog/token',
         
     | 
| 
      
 230 
     | 
    
         
            +
                        'https://arbiscan.io/token'
         
     | 
| 
      
 231 
     | 
    
         
            +
                    ],
         
     | 
| 
      
 232 
     | 
    
         
            +
                    Chains.optimism: [
         
     | 
| 
      
 233 
     | 
    
         
            +
                        # 'https://optimistic-etherscan-io.translate.goog/token',
         
     | 
| 
      
 234 
     | 
    
         
            +
                        'https://optimistic.etherscan.io/token'
         
     | 
| 
      
 235 
     | 
    
         
            +
                    ],
         
     | 
| 
      
 236 
     | 
    
         
            +
                    # Chains.avalanche: [
         
     | 
| 
      
 237 
     | 
    
         
            +
                    #     'https://snowtrace.io/token'
         
     | 
| 
      
 238 
     | 
    
         
            +
                    # ],
         
     | 
| 
      
 239 
     | 
    
         
            +
                    Chains.cronos: ['https://cronoscan.com/token']
         
     | 
| 
      
 240 
     | 
    
         
            +
                }
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
                gg_translate_suffix = '?_x_tr_sl=vi&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp'
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
             
     | 
| 
      
 245 
     | 
    
         
            +
            class Networks:
         
     | 
| 
      
 246 
     | 
    
         
            +
                bsc = 'bsc'
         
     | 
| 
      
 247 
     | 
    
         
            +
                ethereum = 'ethereum'
         
     | 
| 
      
 248 
     | 
    
         
            +
                fantom = 'fantom'
         
     | 
| 
      
 249 
     | 
    
         
            +
                polygon = 'polygon'
         
     | 
| 
      
 250 
     | 
    
         
            +
                arbitrum = 'arbitrum'
         
     | 
| 
      
 251 
     | 
    
         
            +
                optimism = 'optimism'
         
     | 
| 
      
 252 
     | 
    
         
            +
                avalanche = 'avalanche'
         
     | 
| 
      
 253 
     | 
    
         
            +
                tron = 'tron'
         
     | 
| 
      
 254 
     | 
    
         
            +
                cronos = 'cronos'
         
     | 
| 
      
 255 
     | 
    
         
            +
                solana = 'solana'
         
     | 
| 
      
 256 
     | 
    
         
            +
                polkadot = 'polkadot'
         
     | 
| 
      
 257 
     | 
    
         
            +
                oasis_sapphire = 'oasis_sapphire'
         
     | 
| 
      
 258 
     | 
    
         
            +
                oasis_sapphire_testnet = 'oasis_sapphire_testnet'
         
     | 
| 
      
 259 
     | 
    
         
            +
                cosmos = 'cosmos'
         
     | 
| 
      
 260 
     | 
    
         
            +
                oraichain = 'oraichain'
         
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
                providers = {
         
     | 
| 
      
 263 
     | 
    
         
            +
                    bsc: os.getenv('BSC_PROVIDER_URI', 'https://bsc-dataseed1.binance.org/'),
         
     | 
| 
      
 264 
     | 
    
         
            +
                    ethereum: os.getenv('ETHEREUM_PROVIDER_URI', 'https://rpc.ankr.com/eth'),
         
     | 
| 
      
 265 
     | 
    
         
            +
                    fantom: os.getenv('FANTOM_PROVIDER_URI', 'https://rpc.ftm.tools/'),
         
     | 
| 
      
 266 
     | 
    
         
            +
                    polygon: os.getenv('POLYGON_PROVIDER_URI', 'https://polygon-rpc.com'),
         
     | 
| 
      
 267 
     | 
    
         
            +
                    arbitrum: os.getenv('ARBITRUM_PROVIDER_URI', 'https://endpoints.omniatech.io/v1/arbitrum/one/public'),
         
     | 
| 
      
 268 
     | 
    
         
            +
                    optimism: os.getenv('OPTIMISM_PROVIDER_URI', 'https://rpc.ankr.com/optimism'),
         
     | 
| 
      
 269 
     | 
    
         
            +
                    avalanche: os.getenv('AVALANCHE_PROVIDER_URI', 'https://rpc.ankr.com/avalanche'),
         
     | 
| 
      
 270 
     | 
    
         
            +
                    tron: os.getenv('TRON_PROVIDER_URI', 'https://rpc.ankr.com/tron_jsonrpc'),
         
     | 
| 
      
 271 
     | 
    
         
            +
                    cronos: os.getenv('CRONOS_PROVIDER_URI', 'https://evm.cronos.org/'),
         
     | 
| 
      
 272 
     | 
    
         
            +
                    solana: os.getenv('SOLANA_PROVIDER_URI', 'https://crimson-multi-putty.solana-mainnet.quiknode.pro/997174ce6ab5cc9d42cb037e931d18ae1a98346a/'),
         
     | 
| 
      
 273 
     | 
    
         
            +
                    polkadot: os.getenv('POLKADOT_PROVIDER_URI', 'https://late-yolo-diagram.dot-mainnet.quiknode.pro/51a1aaf2372854dfd211fca3ab375e5451222be4/'),
         
     | 
| 
      
 274 
     | 
    
         
            +
                    oasis_sapphire: os.getenv('OASIS_SAPPHIRE_PROVIDER_URI'),
         
     | 
| 
      
 275 
     | 
    
         
            +
                    oasis_sapphire_testnet: os.getenv('OASIS_SAPPHIRE_PROVIDER_URI')
         
     | 
| 
      
 276 
     | 
    
         
            +
                }
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
      
 278 
     | 
    
         
            +
                archive_node = {
         
     | 
| 
      
 279 
     | 
    
         
            +
                    bsc: os.getenv('BSC_PROVIDER_ARCHIVE_URI', 'https://rpc.ankr.com/bsc'),
         
     | 
| 
      
 280 
     | 
    
         
            +
                    ethereum: os.getenv('ETHEREUM_PROVIDER_ARCHIVE_URI', 'https://rpc.ankr.com/eth'),
         
     | 
| 
      
 281 
     | 
    
         
            +
                    fantom: os.getenv('FANTOM_PROVIDER_ARCHIVE_URI', 'https://rpc.ankr.com/fantom'),
         
     | 
| 
      
 282 
     | 
    
         
            +
                    polygon: os.getenv('POLYGON_PROVIDER_ARCHIVE_URI', 'https://rpc.ankr.com/polygon'),
         
     | 
| 
      
 283 
     | 
    
         
            +
                    arbitrum: os.getenv('ARBITRUM_PROVIDER_ARCHIVE_URI', 'https://rpc.ankr.com/arbitrum'),
         
     | 
| 
      
 284 
     | 
    
         
            +
                    optimism: os.getenv('OPTIMISM_PROVIDER_ARCHIVE_URI', 'https://rpc.ankr.com/optimism'),
         
     | 
| 
      
 285 
     | 
    
         
            +
                    avalanche: os.getenv('AVALANCHE_PROVIDER_ARCHIVE_URI', 'https://rpc.ankr.com/avalanche'),
         
     | 
| 
      
 286 
     | 
    
         
            +
                    tron: os.getenv('TRON_PROVIDER_ARCHIVE_URI', 'https://rpc.ankr.com/tron_jsonrpc'),
         
     | 
| 
      
 287 
     | 
    
         
            +
                    cronos: os.getenv('CRONOS_PROVIDER_ARCHIVE_URI'),
         
     | 
| 
      
 288 
     | 
    
         
            +
                    solana: os.getenv('SOLANA_PROVIDER_ARCHIVE_URI'),
         
     | 
| 
      
 289 
     | 
    
         
            +
                    polkadot: os.getenv('POLKADOT_PROVIDER_ARCHIVE_URI'),
         
     | 
| 
      
 290 
     | 
    
         
            +
                    oasis_sapphire: os.getenv('OASIS_SAPPHIRE_PROVIDER_ARCHIVE_URI'),
         
     | 
| 
      
 291 
     | 
    
         
            +
                    oasis_sapphire_testnet: os.getenv('OASIS_SAPPHIRE_PROVIDER_ARCHIVE_URI')
         
     | 
| 
      
 292 
     | 
    
         
            +
                }
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
             
     | 
| 
      
 295 
     | 
    
         
            +
            class DefiLlama:
         
     | 
| 
      
 296 
     | 
    
         
            +
                chains = {
         
     | 
| 
      
 297 
     | 
    
         
            +
                    'Binance': Chains.bsc,
         
     | 
| 
      
 298 
     | 
    
         
            +
                    'Ethereum': Chains.ethereum,
         
     | 
| 
      
 299 
     | 
    
         
            +
                    'Fantom': Chains.fantom,
         
     | 
| 
      
 300 
     | 
    
         
            +
                    'Polygon': Chains.polygon,
         
     | 
| 
      
 301 
     | 
    
         
            +
                    'Arbitrum': Chains.arbitrum,
         
     | 
| 
      
 302 
     | 
    
         
            +
                    'Optimism': Chains.optimism,
         
     | 
| 
      
 303 
     | 
    
         
            +
                    'Avalanche': Chains.avalanche,
         
     | 
| 
      
 304 
     | 
    
         
            +
                    'Tron': Chains.tron,
         
     | 
| 
      
 305 
     | 
    
         
            +
                    'Cronos': Chains.cronos,
         
     | 
| 
      
 306 
     | 
    
         
            +
                    'Solana': Chains.solana,
         
     | 
| 
      
 307 
     | 
    
         
            +
                    'Polkadot': Chains.polkadot,
         
     | 
| 
      
 308 
     | 
    
         
            +
                    'Base': Chains.base,
         
     | 
| 
      
 309 
     | 
    
         
            +
                    'Kava': Chains.kava,
         
     | 
| 
      
 310 
     | 
    
         
            +
                    'xDai': Chains.gnosis,
         
     | 
| 
      
 311 
     | 
    
         
            +
                    'Klaytn': Chains.klaytn,
         
     | 
| 
      
 312 
     | 
    
         
            +
                    'Mantle': Chains.mantle,
         
     | 
| 
      
 313 
     | 
    
         
            +
                    'Celo': Chains.celo,
         
     | 
| 
      
 314 
     | 
    
         
            +
                    'Moonbeam': Chains.moonbeam,
         
     | 
| 
      
 315 
     | 
    
         
            +
                    'Manta': Chains.manta,
         
     | 
| 
      
 316 
     | 
    
         
            +
                    'Pulse': Chains.pulse,
         
     | 
| 
      
 317 
     | 
    
         
            +
                    'RSK': Chains.rootstock,
         
     | 
| 
      
 318 
     | 
    
         
            +
                    'Astar': Chains.astar,
         
     | 
| 
      
 319 
     | 
    
         
            +
                    'Metis': Chains.metis,
         
     | 
| 
      
 320 
     | 
    
         
            +
                    'Canto': Chains.canto,
         
     | 
| 
      
 321 
     | 
    
         
            +
                    'Heco': Chains.heco,
         
     | 
| 
      
 322 
     | 
    
         
            +
                    'Linea': Chains.linea,
         
     | 
| 
      
 323 
     | 
    
         
            +
                    'OKExChain': Chains.okc,
         
     | 
| 
      
 324 
     | 
    
         
            +
                    'Aurora': Chains.aurora,
         
     | 
| 
      
 325 
     | 
    
         
            +
                    'Moonriver': Chains.moonriver,
         
     | 
| 
      
 326 
     | 
    
         
            +
                    'Oasis Sapphire': Chains.oasis_sapphire,
         
     | 
| 
      
 327 
     | 
    
         
            +
                    'Blast': Chains.blast,
         
     | 
| 
      
 328 
     | 
    
         
            +
                    'Oraichain': Chains.oraichain
         
     | 
| 
      
 329 
     | 
    
         
            +
                }
         
     | 
| 
      
 330 
     | 
    
         
            +
             
     | 
| 
      
 331 
     | 
    
         
            +
             
     | 
| 
      
 332 
     | 
    
         
            +
            class Opensea:
         
     | 
| 
      
 333 
     | 
    
         
            +
                chains = {
         
     | 
| 
      
 334 
     | 
    
         
            +
                    Chains.bsc: 'BSC',
         
     | 
| 
      
 335 
     | 
    
         
            +
                    Chains.ethereum: 'ETHEREUM',
         
     | 
| 
      
 336 
     | 
    
         
            +
                    Chains.polygon: 'MATIC',
         
     | 
| 
      
 337 
     | 
    
         
            +
                    Chains.fantom: 'FANTOM',
         
     | 
| 
      
 338 
     | 
    
         
            +
                    Chains.arbitrum: 'ARBITRUM',
         
     | 
| 
      
 339 
     | 
    
         
            +
                    Chains.optimism: 'OPTIMISM',
         
     | 
| 
      
 340 
     | 
    
         
            +
                    Chains.avalanche: 'AVALANCHE',
         
     | 
| 
      
 341 
     | 
    
         
            +
                    Chains.tron: 'TRON',
         
     | 
| 
      
 342 
     | 
    
         
            +
                    Chains.solana: 'SOLANA',
         
     | 
| 
      
 343 
     | 
    
         
            +
                    Chains.base: 'BASE',
         
     | 
| 
      
 344 
     | 
    
         
            +
                    Chains.klaytn: 'KLAYTN'
         
     | 
| 
      
 345 
     | 
    
         
            +
                }
         
     | 
| 
      
 346 
     | 
    
         
            +
             
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
      
 348 
     | 
    
         
            +
            NATIVE_TOKEN = '0x0000000000000000000000000000000000000000'
         
     | 
| 
      
 349 
     | 
    
         
            +
             
     | 
| 
      
 350 
     | 
    
         
            +
            NATIVE_TOKENS = {
         
     | 
| 
      
 351 
     | 
    
         
            +
                Chains.bsc: '0x0000000000000000000000000000000000000000',
         
     | 
| 
      
 352 
     | 
    
         
            +
                Chains.ethereum: '0x0000000000000000000000000000000000000000',
         
     | 
| 
      
 353 
     | 
    
         
            +
                Chains.fantom: '0x0000000000000000000000000000000000000000',
         
     | 
| 
      
 354 
     | 
    
         
            +
                Chains.polygon: '0x0000000000000000000000000000000000000000',
         
     | 
| 
      
 355 
     | 
    
         
            +
                Chains.arbitrum: '0x0000000000000000000000000000000000000000',
         
     | 
| 
      
 356 
     | 
    
         
            +
                Chains.optimism: '0x0000000000000000000000000000000000000000',
         
     | 
| 
      
 357 
     | 
    
         
            +
                Chains.avalanche: '0x0000000000000000000000000000000000000000',
         
     | 
| 
      
 358 
     | 
    
         
            +
                Chains.tron: '0x0000000000000000000000000000000000000000'
         
     | 
| 
      
 359 
     | 
    
         
            +
            }
         
     | 
| 
      
 360 
     | 
    
         
            +
             
     | 
| 
      
 361 
     | 
    
         
            +
             
     | 
| 
      
 362 
     | 
    
         
            +
            class MulticallContract:
         
     | 
| 
      
 363 
     | 
    
         
            +
                """
         
     | 
| 
      
 364 
     | 
    
         
            +
                References: https://www.multicall3.com/deployments
         
     | 
| 
      
 365 
     | 
    
         
            +
                """
         
     | 
| 
      
 366 
     | 
    
         
            +
             
     | 
| 
      
 367 
     | 
    
         
            +
                on_chains_v3 = {
         
     | 
| 
      
 368 
     | 
    
         
            +
                    Chains.ethereum: '0xca11bde05977b3631167028862be2a173976ca11',
         
     | 
| 
      
 369 
     | 
    
         
            +
                    Chains.bsc: '0xca11bde05977b3631167028862be2a173976ca11',
         
     | 
| 
      
 370 
     | 
    
         
            +
                    Chains.polygon: '0xca11bde05977b3631167028862be2a173976ca11',
         
     | 
| 
      
 371 
     | 
    
         
            +
                    Chains.avalanche: '0xca11bde05977b3631167028862be2a173976ca11',
         
     | 
| 
      
 372 
     | 
    
         
            +
                    Chains.fantom: '0xca11bde05977b3631167028862be2a173976ca11',
         
     | 
| 
      
 373 
     | 
    
         
            +
                    Chains.arbitrum: '0xca11bde05977b3631167028862be2a173976ca11',
         
     | 
| 
      
 374 
     | 
    
         
            +
                    Chains.optimism: '0xca11bde05977b3631167028862be2a173976ca11',
         
     | 
| 
      
 375 
     | 
    
         
            +
                    Chains.tron: '0x32a4f47a74a6810bd0bf861cabab99656a75de9e',
         
     | 
| 
      
 376 
     | 
    
         
            +
                    Chains.oasis_sapphire: '0xca11bde05977b3631167028862be2a173976ca11',
         
     | 
| 
      
 377 
     | 
    
         
            +
                    Chains.oasis_sapphire_testnet: '0xca11bde05977b3631167028862be2a173976ca11'
         
     | 
| 
      
 378 
     | 
    
         
            +
                }
         
     | 
| 
      
 379 
     | 
    
         
            +
             
     | 
| 
      
 380 
     | 
    
         
            +
                default_address = '0xca11bde05977b3631167028862be2a173976ca11'
         
     | 
| 
      
 381 
     | 
    
         
            +
             
     | 
| 
      
 382 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 383 
     | 
    
         
            +
                def get_multicall_contract(cls, chain_id):
         
     | 
| 
      
 384 
     | 
    
         
            +
                    return cls.on_chains_v3.get(chain_id, cls.default_address)
         
     | 
| 
      
 385 
     | 
    
         
            +
             
     | 
| 
      
 386 
     | 
    
         
            +
             
     | 
| 
      
 387 
     | 
    
         
            +
            EMPTY_TOKEN_IMG = 'https://firebasestorage.googleapis.com/v0/b/token-c515a.appspot.com/o/tokens_v2%2Fempty-token.png?alt=media&token=2f9dfcc1-88a0-472c-a51f-4babc0c583f0'
         
     | 
| 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import logging
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            from defi_services.constants.chain_constant import Chain
         
     | 
| 
      
 4 
     | 
    
         
            +
            from defi_services.constants.query_constant import Query
         
     | 
| 
      
 5 
     | 
    
         
            +
            from defi_services.jobs.processors.state_processor import StateProcessor
         
     | 
| 
      
 6 
     | 
    
         
            +
            from defi_services.jobs.queriers.multicall_state_querier import MulticallStateQuerier
         
     | 
| 
      
 7 
     | 
    
         
            +
            from defi_services.utils.convert_address import base58_to_hex
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            logger = logging.getLogger("MulticallStateProcessor")
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            class MulticallStateProcessor(StateProcessor):
         
     | 
| 
      
 13 
     | 
    
         
            +
                def __init__(self, provider_uri: str, chain_id: str):
         
     | 
| 
      
 14 
     | 
    
         
            +
                    super().__init__(provider_uri, chain_id)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    self.state_querier = MulticallStateQuerier(provider_uri, chain_id)
         
     | 
| 
         @@ -0,0 +1,101 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import logging
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            from web3 import Web3
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            from defi_services.abis.multicall_v3_abi import MULTICALL_V3_ABI
         
     | 
| 
      
 6 
     | 
    
         
            +
            from defi_services.constants.network_constants import MulticallContract
         
     | 
| 
      
 7 
     | 
    
         
            +
            from defi_services.constants.query_constant import Query
         
     | 
| 
      
 8 
     | 
    
         
            +
            from defi_services.constants.token_constant import Token
         
     | 
| 
      
 9 
     | 
    
         
            +
            from defi_services.jobs.queriers.state_querier import StateQuerier
         
     | 
| 
      
 10 
     | 
    
         
            +
            from defi_services.services.multicall.batch_queries_service import decode_data_response_ignore_error, \
         
     | 
| 
      
 11 
     | 
    
         
            +
                decode_data_response
         
     | 
| 
      
 12 
     | 
    
         
            +
            from defi_services.services.multicall.multicall_v2 import W3Multicall, add_rpc_multicall
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            logger = logging.getLogger("MulticallStateQuerier")
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            class MulticallStateQuerier(StateQuerier):
         
     | 
| 
      
 18 
     | 
    
         
            +
                def __init__(self, provider_uri, chain_id):
         
     | 
| 
      
 19 
     | 
    
         
            +
                    super().__init__(provider_uri)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    self.chain_id = chain_id
         
     | 
| 
      
 21 
     | 
    
         
            +
                    self.multicall_address = Web3.to_checksum_address(MulticallContract.get_multicall_contract(self.chain_id))
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def query_state_data(self, queries: dict, batch_size: int = 100, workers: int = 5, ignore_error: bool = False):
         
     | 
| 
      
 24 
     | 
    
         
            +
                    """
         
     | 
| 
      
 25 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 26 
     | 
    
         
            +
                        queries: dict - defi state queries
         
     | 
| 
      
 27 
     | 
    
         
            +
                            - key: str - id of query
         
     | 
| 
      
 28 
     | 
    
         
            +
                            - value: dict - input of query
         
     | 
| 
      
 29 
     | 
    
         
            +
                                {
         
     | 
| 
      
 30 
     | 
    
         
            +
                                    address: str - address of contract
         
     | 
| 
      
 31 
     | 
    
         
            +
                                    abi: list - abi of contract,
         
     | 
| 
      
 32 
     | 
    
         
            +
                                    function: str - name of the function,
         
     | 
| 
      
 33 
     | 
    
         
            +
                                    params: list - list parameters of function,
         
     | 
| 
      
 34 
     | 
    
         
            +
                                    block_number: int - the block number saving the state data
         
     | 
| 
      
 35 
     | 
    
         
            +
                                }
         
     | 
| 
      
 36 
     | 
    
         
            +
                        batch_size: int - number of query in each batch queries
         
     | 
| 
      
 37 
     | 
    
         
            +
                        workers: int - maximum number of vCPU used in queries
         
     | 
| 
      
 38 
     | 
    
         
            +
                        ignore_error: bool - ignore error when decode result or not
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    Return:
         
     | 
| 
      
 41 
     | 
    
         
            +
                        + A dictionary result of queries
         
     | 
| 
      
 42 
     | 
    
         
            +
                            - key: str - id of query
         
     | 
| 
      
 43 
     | 
    
         
            +
                            - value: result of query
         
     | 
| 
      
 44 
     | 
    
         
            +
                    """
         
     | 
| 
      
 45 
     | 
    
         
            +
                    w3_multicall = W3Multicall(self._w3, address=self.multicall_address)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    for key, value in queries.items():
         
     | 
| 
      
 47 
     | 
    
         
            +
                        fn_paras = value.get(Query.params)
         
     | 
| 
      
 48 
     | 
    
         
            +
                        block_number = value.get(Query.block_number)
         
     | 
| 
      
 49 
     | 
    
         
            +
                        items = key.split('_')
         
     | 
| 
      
 50 
     | 
    
         
            +
                        if Token.native_token == items[2] and "balanceof" == items[0]:
         
     | 
| 
      
 51 
     | 
    
         
            +
                            w3_multicall.add(W3Multicall.Call(
         
     | 
| 
      
 52 
     | 
    
         
            +
                                self.multicall_address, MULTICALL_V3_ABI, fn_paras=fn_paras,
         
     | 
| 
      
 53 
     | 
    
         
            +
                                fn_name="getEthBalance", block_number=block_number, key=key
         
     | 
| 
      
 54 
     | 
    
         
            +
                            ))
         
     | 
| 
      
 55 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 56 
     | 
    
         
            +
                            abi = value.get(Query.abi)
         
     | 
| 
      
 57 
     | 
    
         
            +
                            contract_address = value.get(Query.address)
         
     | 
| 
      
 58 
     | 
    
         
            +
                            checksum_address = Web3.to_checksum_address(contract_address)
         
     | 
| 
      
 59 
     | 
    
         
            +
                            fn_name = value.get(Query.function)
         
     | 
| 
      
 60 
     | 
    
         
            +
                            w3_multicall.add(W3Multicall.Call(
         
     | 
| 
      
 61 
     | 
    
         
            +
                                checksum_address, abi, fn_name=fn_name,
         
     | 
| 
      
 62 
     | 
    
         
            +
                                fn_paras=fn_paras,
         
     | 
| 
      
 63 
     | 
    
         
            +
                                block_number=block_number, key=key
         
     | 
| 
      
 64 
     | 
    
         
            +
                            ))
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                    list_call_id, list_rpc_call = [], []
         
     | 
| 
      
 67 
     | 
    
         
            +
                    add_rpc_multicall(
         
     | 
| 
      
 68 
     | 
    
         
            +
                        w3_multicall,
         
     | 
| 
      
 69 
     | 
    
         
            +
                        list_rpc_call=list_rpc_call, list_call_id=list_call_id,
         
     | 
| 
      
 70 
     | 
    
         
            +
                        batch_size=batch_size
         
     | 
| 
      
 71 
     | 
    
         
            +
                    )
         
     | 
| 
      
 72 
     | 
    
         
            +
                    response_data = self.client_querier.sent_batch_to_provider(list_rpc_call, batch_size, workers)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    filtered_response_data = {}
         
     | 
| 
      
 74 
     | 
    
         
            +
                    # loại bỏ những phần tử không có data
         
     | 
| 
      
 75 
     | 
    
         
            +
                    for key, value in response_data.items():
         
     | 
| 
      
 76 
     | 
    
         
            +
                        if value is not None:
         
     | 
| 
      
 77 
     | 
    
         
            +
                            filtered_response_data[key] = value
         
     | 
| 
      
 78 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 79 
     | 
    
         
            +
                            logger.info(key)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    filtered_keys = list(filtered_response_data.keys())
         
     | 
| 
      
 81 
     | 
    
         
            +
                    response_data = filtered_response_data
         
     | 
| 
      
 82 
     | 
    
         
            +
                    list_call_id = [call_id for call_id in list_call_id if call_id in filtered_keys]
         
     | 
| 
      
 83 
     | 
    
         
            +
                    decoded_data = self.decode_response_data(
         
     | 
| 
      
 84 
     | 
    
         
            +
                        response_data, list_call_id, ignore_error=ignore_error, w3_multicall=w3_multicall, batch_size=batch_size)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    return decoded_data
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                def decode_response_data(
         
     | 
| 
      
 88 
     | 
    
         
            +
                        self, response_data: dict, list_call_id: list, ignore_error=False, w3_multicall=None, batch_size=100):
         
     | 
| 
      
 89 
     | 
    
         
            +
                    if ignore_error:
         
     | 
| 
      
 90 
     | 
    
         
            +
                        decoded_data = decode_data_response_ignore_error(data_responses=response_data, list_call_id=list_call_id)
         
     | 
| 
      
 91 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 92 
     | 
    
         
            +
                        decoded_data = decode_data_response(data_responses=response_data, list_call_id=list_call_id)
         
     | 
| 
      
 93 
     | 
    
         
            +
                    batch_idx = 0
         
     | 
| 
      
 94 
     | 
    
         
            +
                    results = {}
         
     | 
| 
      
 95 
     | 
    
         
            +
                    for block_number, batch_calls in w3_multicall.batch_calls_iterator(batch_size=batch_size):
         
     | 
| 
      
 96 
     | 
    
         
            +
                        multicall_data = decoded_data.get(f'{batch_idx}_{block_number}')
         
     | 
| 
      
 97 
     | 
    
         
            +
                        decode_multicall_data = w3_multicall.decode(multicall_data, calls=batch_calls, ignore_error=ignore_error)
         
     | 
| 
      
 98 
     | 
    
         
            +
                        results.update(decode_multicall_data)
         
     | 
| 
      
 99 
     | 
    
         
            +
                        batch_idx += 1
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                    return results
         
     | 
| 
         
            File without changes
         
     | 
| 
         @@ -0,0 +1,91 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # MIT License
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Copyright (c) 2018 Evgeny Medvedev, evge.medvedev@gmail.com
         
     | 
| 
      
 4 
     | 
    
         
            +
            #
         
     | 
| 
      
 5 
     | 
    
         
            +
            # Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
      
 6 
     | 
    
         
            +
            # of this software and associated documentation files (the "Software"), to deal
         
     | 
| 
      
 7 
     | 
    
         
            +
            # in the Software without restriction, including without limitation the rights
         
     | 
| 
      
 8 
     | 
    
         
            +
            # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 9 
     | 
    
         
            +
            # copies of the Software, and to permit persons to whom the Software is
         
     | 
| 
      
 10 
     | 
    
         
            +
            # furnished to do so, subject to the following conditions:
         
     | 
| 
      
 11 
     | 
    
         
            +
            #
         
     | 
| 
      
 12 
     | 
    
         
            +
            # The above copyright notice and this permission notice shall be included in all
         
     | 
| 
      
 13 
     | 
    
         
            +
            # copies or substantial portions of the Software.
         
     | 
| 
      
 14 
     | 
    
         
            +
            #
         
     | 
| 
      
 15 
     | 
    
         
            +
            # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 16 
     | 
    
         
            +
            # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 17 
     | 
    
         
            +
            # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         
     | 
| 
      
 18 
     | 
    
         
            +
            # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 19 
     | 
    
         
            +
            # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 20 
     | 
    
         
            +
            # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         
     | 
| 
      
 21 
     | 
    
         
            +
            # SOFTWARE.
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            from datetime import datetime, timezone
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            from defi_services.utils.graph_operations import GraphOperations, OutOfBoundsError, Point
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            class EthService(object):
         
     | 
| 
      
 30 
     | 
    
         
            +
                def __init__(self, web3):
         
     | 
| 
      
 31 
     | 
    
         
            +
                    graph = BlockTimestampGraph(web3)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    self._graph_operations = GraphOperations(graph)
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def get_block_for_timestamp(self, timestamp):
         
     | 
| 
      
 35 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 36 
     | 
    
         
            +
                        block_bounds = self._graph_operations.get_bounds_for_y_coordinate(timestamp)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    except OutOfBoundsError:
         
     | 
| 
      
 38 
     | 
    
         
            +
                        return 'latest'
         
     | 
| 
      
 39 
     | 
    
         
            +
                    return block_bounds[0]
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                def get_block_range_for_date(self, date):
         
     | 
| 
      
 42 
     | 
    
         
            +
                    start_datetime = datetime.combine(date, datetime.min.time().replace(tzinfo=timezone.utc))
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end_datetime = datetime.combine(date, datetime.max.time().replace(tzinfo=timezone.utc))
         
     | 
| 
      
 44 
     | 
    
         
            +
                    return self.get_block_range_for_timestamps(start_datetime.timestamp(), end_datetime.timestamp())
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                def get_block_range_for_timestamps(self, start_timestamp, end_timestamp):
         
     | 
| 
      
 47 
     | 
    
         
            +
                    start_timestamp = int(start_timestamp)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end_timestamp = int(end_timestamp)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    if start_timestamp > end_timestamp:
         
     | 
| 
      
 50 
     | 
    
         
            +
                        raise ValueError('start_timestamp must be greater or equal to end_timestamp')
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 53 
     | 
    
         
            +
                        start_block_bounds = self._graph_operations.get_bounds_for_y_coordinate(start_timestamp)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    except OutOfBoundsError:
         
     | 
| 
      
 55 
     | 
    
         
            +
                        start_block_bounds = (0, 0)
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 58 
     | 
    
         
            +
                        end_block_bounds = self._graph_operations.get_bounds_for_y_coordinate(end_timestamp)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    except OutOfBoundsError as e:
         
     | 
| 
      
 60 
     | 
    
         
            +
                        raise OutOfBoundsError('The existing blocks do not completely cover the given time range') from e
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    if start_block_bounds == end_block_bounds and start_block_bounds[0] != start_block_bounds[1]:
         
     | 
| 
      
 63 
     | 
    
         
            +
                        raise ValueError('The given timestamp range does not cover any blocks')
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                    start_block = start_block_bounds[1]
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end_block = end_block_bounds[0]
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    # The genesis block has timestamp 0 but we include it with the 1st block.
         
     | 
| 
      
 69 
     | 
    
         
            +
                    if start_block == 1:
         
     | 
| 
      
 70 
     | 
    
         
            +
                        start_block = 0
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    return start_block, end_block
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
            class BlockTimestampGraph(object):
         
     | 
| 
      
 76 
     | 
    
         
            +
                def __init__(self, web3):
         
     | 
| 
      
 77 
     | 
    
         
            +
                    self._web3 = web3
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                def get_first_point(self):
         
     | 
| 
      
 80 
     | 
    
         
            +
                    # Ignore the genesis block as its timestamp is 0
         
     | 
| 
      
 81 
     | 
    
         
            +
                    return block_to_point(self._web3.eth.get_block(1))
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                def get_last_point(self):
         
     | 
| 
      
 84 
     | 
    
         
            +
                    return block_to_point(self._web3.eth.get_block('latest'))
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                def get_point(self, x):
         
     | 
| 
      
 87 
     | 
    
         
            +
                    return block_to_point(self._web3.eth.get_block(x))
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
            def block_to_point(block):
         
     | 
| 
      
 91 
     | 
    
         
            +
                return Point(block.number, block.timestamp)
         
     | 
| 
         
            File without changes
         
     |