def pairs_from_ethereum(ethereum: EthereumManager) -> Dict[str, Any]: """Detect the uniswap v2 pool tokens by using an ethereum node""" contracts_file = Path(__file__).resolve().parent / 'contracts.json' with contracts_file.open('r') as f: contracts = json.loads(f.read()) univ2factory = EthereumContract( address=contracts['UNISWAPV2FACTORY']['address'], abi=contracts['UNISWAPV2FACTORY']['abi'], deployed_block=0, # whatever ) pairs_num = univ2factory.call(ethereum, 'allPairsLength') chunks = list(get_chunks([[x] for x in range(pairs_num)], n=500)) pairs = [] for idx, chunk in enumerate(chunks): print(f'Querying univ2 pairs chunk {idx + 1} / {len(chunks)}') result = multicall_specific(ethereum, univ2factory, 'allPairs', chunk) try: pairs.extend([deserialize_ethereum_address(x[0]) for x in result]) except DeserializationError: print( 'Error deserializing address while fetching uniswap v2 pool tokens' ) sys.exit(1) return pairs
def _decode_order_placement( # pylint: disable=no-self-use self, tx_log: EthereumTxReceiptLog, transaction: EthereumTransaction, # pylint: disable=unused-argument decoded_events: List[HistoryBaseEntry], # pylint: disable=unused-argument all_logs: List[EthereumTxReceiptLog], # pylint: disable=unused-argument action_items: List[ActionItem], # pylint: disable=unused-argument ) -> Tuple[Optional[HistoryBaseEntry], Optional[ActionItem]]: """Some docs: https://docs.gnosis.io/protocol/docs/tutorial-limit-orders/""" topic_data, log_data = self.contract.decode_event( tx_log=tx_log, event_name='OrderPlacement', argument_names=('owner', 'index', 'buyToken', 'sellToken', 'validFrom', 'validUntil', 'priceNumerator', 'priceDenominator'), # noqa: E501 ) owner = topic_data[0] if not self.base.is_tracked(owner): return None, None result = multicall_specific( ethereum=self.ethereum, contract=self.contract, method_name='tokenIdToAddressMap', arguments=[[topic_data[1]], [topic_data[2]]], ) # The resulting addresses are non checksumed but they can be found in the DB buy_token = ethaddress_to_asset(result[0][0]) if buy_token is None: return None, None sell_token = ethaddress_to_asset(result[1][0]) if sell_token is None: return None, None buy_amount = asset_normalized_value(amount=log_data[3], asset=buy_token) sell_amount = asset_normalized_value(amount=log_data[4], asset=sell_token) event = HistoryBaseEntry( event_identifier=transaction.tx_hash.hex(), sequence_index=self.base.get_sequence_index(tx_log), timestamp=ts_sec_to_ms(transaction.timestamp), location=Location.BLOCKCHAIN, location_label=owner, # Asset means nothing here since the event is informational. TODO: Improve? asset=sell_token, balance=Balance(amount=sell_amount), notes= f'Place an order in DXDao Mesa to sell {sell_amount} {sell_token.symbol} for {buy_amount} {buy_token.symbol}', # noqa: E501 event_type=HistoryEventType.INFORMATIONAL, event_subtype=HistoryEventSubType.PLACE_ORDER, counterparty=CPT_DXDAO_MESA, ) return event, None
def query_defi_balances( self, addresses: List[ChecksumEthAddress], ) -> Dict[ChecksumEthAddress, List[DefiProtocolBalances]]: defi_balances = defaultdict(list) for account in addresses: balances = self.zerion_sdk.all_balances_for_account(account) if len(balances) != 0: defi_balances[account] = balances # and also query balances of tokens that are not detected by zerion adapter contract result = multicall_specific( ethereum=self.ethereum, contract=VOTE_ESCROWED_CRV, method_name='locked', arguments=[[x] for x in addresses], ) crv_price = Price(ZERO) if any(x[0] != 0 for x in result): crv_price = Inquirer().find_usd_price(A_CRV) for idx, address in enumerate(addresses): balance = result[idx][0] if balance == 0: continue # else the address has vote escrowed CRV amount = token_normalized_value_decimals(token_amount=balance, token_decimals=18) protocol_balance = DefiProtocolBalances( protocol=DefiProtocol( name='Curve • Vesting', description='Curve vesting or locked in escrow for voting', url='https://www.curve.fi/', version=1, ), balance_type='Asset', base_balance=DefiBalance( token_address=VOTE_ESCROWED_CRV.address, token_name='Vote-escrowed CRV', token_symbol='veCRV', balance=Balance( amount=amount, usd_value=amount * crv_price, ), ), underlying_balances=[], ) defi_balances[address].append(protocol_balance) return defi_balances
def get_balances( self, addresses: List[ChecksumAddress], ) -> Dict[ChecksumAddress, Balance]: """Return the addresses' balances (staked amount per pool) in the AdEx protocol. May raise: - RemoteError: Problem querying the chain """ if len(addresses) == 0: return {} result = multicall_specific( ethereum=self.ethereum, contract=self.staking_pool, method_name='balanceOf', arguments=[[x] for x in addresses], ) if all(x[0] == 0 for x in result): return {} # no balances found staking_balances = {} usd_price = Inquirer().find_usd_price(A_ADX) share_price = self.staking_pool.call(self.ethereum, 'shareValue') for idx, address in enumerate(addresses): balance = result[idx][0] if balance == 0: continue # else the address has staked adex amount = token_normalized_value_decimals( token_amount=balance * share_price / (FVal(10)**18), token_decimals=18, ) staking_balances[address] = Balance(amount=amount, usd_value=amount * usd_price) return staking_balances
def get_pool( self, token_0: EthereumToken, token_1: EthereumToken, ) -> List[str]: result = multicall_specific( ethereum=self.eth_manager, contract=UNISWAP_V3_FACTORY, method_name='getPool', arguments=[[ token_0.ethereum_address, token_1.ethereum_address, fee, ] for fee in (3000, 500, 10000)], ) # get liquidity for each pool and choose the pool with the highest liquidity best_pool, max_liquidity = to_checksum_address(result[0][0]), 0 for query in result: if query[0] == ZERO_ADDRESS: continue pool_address = to_checksum_address(query[0]) pool_contract = EthereumContract( address=pool_address, abi=UNISWAP_V3_POOL_ABI, deployed_block=UNISWAP_FACTORY_DEPLOYED_BLOCK, ) pool_liquidity = pool_contract.call( ethereum=self.eth_manager, method_name='liquidity', arguments=[], call_order=None, ) if pool_liquidity > max_liquidity: best_pool = pool_address return [best_pool]