예제 #1
0
    def get_eth_balance(self, account: typing.EthAddress) -> FVal:
        if not self.connected:
            log.debug(
                'Querying etherscan for account balance',
                sensitive_log=True,
                eth_address=account,
            )
            eth_resp = request_get_dict(
                'https://api.etherscan.io/api?module=account&action=balance&address=%s'
                % account, )
            if eth_resp['status'] != 1:
                raise ValueError(
                    'Failed to query etherscan for accounts balance')
            amount = FVal(eth_resp['result'])

            log.debug(
                'Etherscan account balance result',
                sensitive_log=True,
                eth_address=account,
                wei_amount=amount,
            )
            return from_wei(amount)
        else:
            wei_amount = self.web3.eth.getBalance(account)  # pylint: disable=no-member
            log.debug(
                'Ethereum node account balance result',
                sensitive_log=True,
                eth_address=account,
                wei_amount=wei_amount,
            )
            return from_wei(wei_amount)
예제 #2
0
    def get_multieth_balance(
        self,
        accounts: List[typing.EthAddress],
    ) -> Dict[typing.EthAddress, FVal]:
        """Returns a dict with keys being accounts and balances in ETH"""
        balances = {}

        if not self.connected:
            if len(accounts) > 20:
                new_accounts = [
                    accounts[x:x + 2] for x in range(0, len(accounts), 2)
                ]
            else:
                new_accounts = [accounts]

            for account_slice in new_accounts:
                log.debug(
                    'Querying etherscan for multiple accounts balance',
                    sensitive_log=True,
                    eth_accounts=account_slice,
                )
                eth_resp = request_get_dict(
                    'https://api.etherscan.io/api?module=account&action=balancemulti&address=%s'
                    % ','.join(account_slice), )
                if eth_resp['status'] != 1:
                    raise ValueError(
                        'Failed to query etherscan for accounts balance')
                eth_accounts = eth_resp['result']

                for account_entry in eth_accounts:
                    amount = FVal(account_entry['balance'])
                    balances[account_entry['account']] = from_wei(amount)
                    log.debug(
                        'Etherscan account balance result',
                        sensitive_log=True,
                        eth_address=account_entry['account'],
                        wei_amount=amount,
                    )

        else:
            for account in accounts:
                amount = FVal(self.web3.eth.getBalance(account))  # pylint: disable=no-member
                log.debug(
                    'Ethereum node balance result',
                    sensitive_log=True,
                    eth_address=account,
                    wei_amount=amount,
                )
                balances[account] = from_wei(amount)

        return balances
예제 #3
0
    def query_eth_highest_block() -> Optional[int]:
        """ Attempts to query blockcypher for the block height

        Returns the highest blockNumber"""

        url = 'https://api.blockcypher.com/v1/eth/main'
        log.debug('Querying ETH highest block', url=url)
        eth_resp = request_get_dict(url)

        if 'height' not in eth_resp:
            return None
        block_number = int(eth_resp['height'])
        log.debug('ETH highest block result', block=block_number)
        return block_number
예제 #4
0
def _query_exchanges_rateapi(base: FiatAsset,
                             quote: FiatAsset) -> Optional[FVal]:
    log.debug(
        'Querying api.exchangeratesapi.io fiat pair',
        base_currency=base,
        quote_currency=quote,
    )
    querystr = f'https://api.exchangeratesapi.io/latest?base={base}&symbols={quote}'
    try:
        resp = request_get_dict(querystr)
        return FVal(resp['rates'][quote])
    except (ValueError, RemoteError, KeyError):
        log.error(
            'Querying api.exchangeratesapi.io for fiat pair failed',
            base_currency=base,
            quote_currency=quote,
        )
        return None
예제 #5
0
def _query_currency_converterapi(base: FiatAsset,
                                 quote: FiatAsset) -> Optional[FVal]:
    log.debug(
        'Query free.currencyconverterapi.com fiat pair',
        base_currency=base,
        quote_currency=quote,
    )
    pair = f'{base}_{quote}'
    querystr = (f'https://free.currencyconverterapi.com/api/v6/convert?'
                f'q={pair}&apiKey={CURRENCYCONVERTER_API_KEY}')
    try:
        resp = request_get_dict(querystr)
        return FVal(resp['results'][pair]['val'])
    except (ValueError, RemoteError, KeyError):
        log.error(
            'Querying free.currencyconverterapi.com fiat pair failed',
            base_currency=base,
            quote_currency=quote,
        )
        return None
예제 #6
0
 def _query_currency_converterapi(self, base: FiatAsset,
                                  quote: FiatAsset) -> Optional[FVal]:
     log.debug(
         'Query free.currencyconverterapi.com fiat pair',
         base_currency=base,
         quote_currency=quote,
     )
     pair = '{}_{}'.format(base, quote)
     querystr = 'https://free.currencyconverterapi.com/api/v5/convert?q={}'.format(
         pair)
     try:
         resp = request_get_dict(querystr)
         return FVal(resp['results'][pair]['val'])
     except (ValueError, RemoteError, KeyError):
         log.error(
             'Querying free.currencyconverterapi.com fiat pair failed',
             base_currency=base,
             quote_currency=quote,
         )
         return None
예제 #7
0
    def get_multitoken_balance(
        self,
        token_symbol: typing.EthToken,
        token_address: typing.EthAddress,
        token_decimals: int,
        accounts: List[typing.EthAddress],
    ) -> Dict[typing.EthAddress, FVal]:
        """Return a dictionary with keys being accounts and value balances of token
        Balance value is normalized through the token decimals.
        """
        balances = {}
        if self.connected:
            token_contract = self.web3.eth.contract(  # pylint: disable=no-member
                address=token_address,
                abi=self.token_abi,
            )

            for account in accounts:
                log.debug(
                    'Ethereum node query for token balance',
                    sensitive_log=True,
                    eth_address=account,
                    token_address=token_address,
                    token_symbol=token_symbol,
                )
                token_amount = FVal(
                    token_contract.functions.balanceOf(account).call())
                if token_amount != 0:
                    balances[account] = token_amount / (FVal(10)**
                                                        FVal(token_decimals))
                log.debug(
                    'Ethereum node result for token balance',
                    sensitive_log=True,
                    eth_address=account,
                    token_address=token_address,
                    token_symbol=token_symbol,
                    amount=token_amount,
                )
        else:
            for account in accounts:
                log.debug(
                    'Querying Etherscan for token balance',
                    sensitive_log=True,
                    eth_address=account,
                    token_address=token_address,
                    token_symbol=token_symbol,
                )
                resp = request_get_dict(
                    'https://api.etherscan.io/api?module=account&action='
                    'tokenbalance&contractaddress={}&address={}'.format(
                        token_address,
                        account,
                    ))
                if resp['status'] != 1:
                    raise ValueError(
                        'Failed to query etherscan for {} token balance of {}'.
                        format(
                            token_symbol,
                            account,
                        ))
                token_amount = FVal(resp['result'])
                if token_amount != 0:
                    balances[account] = token_amount / (FVal(10)**
                                                        FVal(token_decimals))
                log.debug(
                    'Etherscan result for token balance',
                    sensitive_log=True,
                    eth_address=account,
                    token_address=token_address,
                    token_symbol=token_symbol,
                    amount=token_amount,
                )

        return balances
예제 #8
0
def query_ethereum_txlist(
    address: EthAddress,
    internal: bool,
    from_block: int = None,
    to_block: int = None,
) -> List[EthereumTransaction]:
    log.debug(
        'Querying etherscan for tx list',
        sensitive_log=True,
        internal=internal,
        eth_address=address,
        from_block=from_block,
        to_block=to_block,
    )

    result = list()
    if internal:
        reqstring = ('https://api.etherscan.io/api?module=account&action='
                     'txlistinternal&address={}'.format(address))
    else:
        reqstring = ('https://api.etherscan.io/api?module=account&action='
                     'txlist&address={}'.format(address))
    if from_block:
        reqstring += '&startblock={}'.format(from_block)
    if to_block:
        reqstring += '&endblock={}'.format(to_block)

    resp = request_get_dict(reqstring)

    if 'status' not in resp or convert_to_int(resp['status']) != 1:
        status = convert_to_int(resp['status'])
        if status == 0 and resp['message'] == 'No transactions found':
            return list()

        log.error(
            'Querying etherscan for tx list failed',
            sensitive_log=True,
            internal=internal,
            eth_address=address,
            from_block=from_block,
            to_block=to_block,
            error=resp['message'],
        )
        # else unknown error
        raise ValueError(
            'Failed to query txlist from etherscan with query: {} . '
            'Response was: {}'.format(reqstring, resp), )

    log.debug('Etherscan tx list query result',
              results_num=len(resp['result']))
    for v in resp['result']:
        # internal tx list contains no gasprice
        gas_price = FVal(-1) if internal else FVal(v['gasPrice'])
        result.append(
            EthereumTransaction(
                timestamp=Timestamp(convert_to_int(v['timeStamp'])),
                block_number=convert_to_int(v['blockNumber']),
                hash=v['hash'],
                from_address=v['from'],
                to_address=v['to'],
                value=FVal(v['value']),
                gas=FVal(v['gas']),
                gas_price=gas_price,
                gas_used=FVal(v['gasUsed']),
            ))

    return result