Exemple #1
0
    def get_utxo(cls, address: str, amount: float):
        data = clove_req_json(
            f'{cls.blockcypher_url()}/addrs/{address}'
            '?limit=2000&unspentOnly=true&includeScript=true&confirmations=6')
        unspent = data.get('txrefs', [])

        for output in unspent:
            output['value'] = int(output['value'])

        unspent = sorted(unspent, key=lambda k: k['value'], reverse=True)

        utxo = []
        total = 0

        for output in unspent:
            value = from_base_units(output['value'])
            utxo.append(
                Utxo(
                    tx_id=output['tx_hash'],
                    vout=output['tx_output_n'],
                    value=value,
                    tx_script=output['script'],
                ))
            total += value
            if total > amount:
                return utxo

        logger.debug(f'Cannot find enough UTXO\'s. Found %.8f from %.8f.',
                     total, amount)
Exemple #2
0
    def get_utxo(cls, address: str, amount: float):
        api_key = os.environ.get('CRYPTOID_API_KEY')
        if not api_key:
            raise ValueError('API key for cryptoid is required to get UTXOs.')
        data = clove_req_json(f'{cls.cryptoid_url()}/api.dws?q=unspent&key={api_key}&active={address}')
        unspent = data.get('unspent_outputs', [])

        for output in unspent:
            output['value'] = int(output['value'])

        unspent = sorted(unspent, key=lambda k: k['value'], reverse=True)

        utxo = []
        total = 0

        for output in unspent:
            value = from_base_units(output['value'])
            utxo.append(
                Utxo(
                    tx_id=output['tx_hash'],
                    vout=output['tx_ouput_n'],
                    value=value,
                    tx_script=output['script'],
                )
            )
            total += value
            if total > amount:
                return utxo

        logger.debug(f'Cannot find enough UTXO\'s. Found %.8f from %.8f.', total, amount)
Exemple #3
0
 def get_balance(cls, wallet_address: str) -> Optional[float]:
     data = clove_req_json(
         f'{cls.blockcypher_url()}/addrs/{wallet_address}/balance')
     if data is None:
         logger.error('Could not get details for address %s in %s network',
                      wallet_address, cls.symbols[0])
         return
     return from_base_units(data['balance'] or data['unconfirmed_balance'])
Exemple #4
0
    def __init__(self,
                 network,
                 contract: str,
                 raw_transaction: Optional[str] = None,
                 transaction_address: Optional[str] = None):

        if not raw_transaction and not transaction_address:
            raise ValueError(
                'Provide raw_transaction or transaction_address argument.')

        self.network = network
        self.symbol = self.network.default_symbol
        self.contract = contract
        self.tx = None
        self.vout = None
        self.confirmations = None
        self.tx_address = transaction_address
        if raw_transaction:
            self.tx = self.network.deserialize_raw_transaction(raw_transaction)
            try:
                self.vout = self.tx.vout[0]
            except IndexError:
                raise ValueError('Given transaction has no outputs.')
        else:
            tx_json = self.network.get_transaction(transaction_address)
            if not tx_json:
                raise ValueError('No transaction found under given address.')

            self.vout = self.network.get_first_vout_from_tx_json(tx_json)
            self.confirmations = self.network.get_confirmations_from_tx_json(
                tx_json)

        if not self.vout:
            raise ValueError('Given transaction has no outputs.')

        contract_tx_out = self.vout
        contract_script = script.CScript.fromhex(self.contract)
        script_pub_key = contract_script.to_p2sh_scriptPubKey()
        valid_p2sh = script_pub_key == contract_tx_out.scriptPubKey
        self.address = str(CBitcoinAddress.from_scriptPubKey(script_pub_key))
        try:
            self.balance = self.network.get_balance(self.address)
        except NotImplementedError:
            self.balance = None

        script_ops = list(contract_script)
        if valid_p2sh and self.is_valid_contract_script(script_ops):
            self.recipient_address = str(
                P2PKHBitcoinAddress.from_bytes(script_ops[6]))
            self.refund_address = str(
                P2PKHBitcoinAddress.from_bytes(script_ops[13]))
            self.locktime_timestamp = int.from_bytes(script_ops[8],
                                                     byteorder='little')
            self.locktime = datetime.utcfromtimestamp(self.locktime_timestamp)
            self.secret_hash = b2x(script_ops[2])
            self.value = from_base_units(contract_tx_out.nValue)
        else:
            raise ValueError('Given transaction is not a valid contract.')
Exemple #5
0
 def get_fee(cls) -> Optional[float]:
     '''Returns actual fee per kb.'''
     response = clove_req_json(cls.fee_endpoint)
     fee = response.get('high_fee_per_kb')
     if not fee:
         logger.error(
             'Cannot find the right key (high_fee_per_kb) while getting fee in blockcypher.'
         )
         return
     return from_base_units(fee)
Exemple #6
0
def get_balance_blockcypher(network: str, address: str,
                            testnet: bool) -> Optional[float]:
    subnet = 'test3' if testnet else 'main'
    url = f'https://api.blockcypher.com/v1/{network.lower()}/{subnet}/addrs/{address}/full?limit=2000'
    data = clove_req_json(url)
    if data is None:
        logger.debug('Could not get details for address %s in %s network',
                     address, network)
        return
    return from_base_units(data['balance'])
Exemple #7
0
    def get_utxo(cls, address: str, amount: float) -> Optional[list]:
        '''
        Getting list of UTXO objects.

        Args:
            address (str): wallet address to look for UTXO
            amount (float): minimum value that should be satisfied in UTXO objects

        Returns:
            list, None: list of UTXO objects or None it there was not enough UTXO

        Example:
            >>> from clove.network import Litecoin
            >>> network = Litecoin()
            >>> network.get_utxo(address='LUAn5PWmsPavgz32mGkqsUuAKncftS37Jq', amount=0.01)
            [
             Utxo(tx_id='0cd90567497823097d03464b4b2d08dd659f1c5621dd55e9540bc9bcd3e191ec', vout='0', value='0.00976168', tx_script='76a91485c0522f6e23beb11cc3d066cd20ed732648a4e688ac', wallet=None, secret=None, refund=False),  # noqa: E501
             Utxo(tx_id='a5c027027c695f403fe570850e35ffd44bb28479ecaaee039372015fe0aae7b2', vout='0', value='0.00097114', tx_script='76a91485c0522f6e23beb11cc3d066cd20ed732648a4e688ac', wallet=None, secret=None, refund=False)  # noqa: E501
            ]
        '''
        data = clove_req_json(
            f'{cls.blockcypher_url()}/addrs/{address}'
            '?limit=2000&unspentOnly=true&includeScript=true&confirmations=6')
        if not data:
            logger.debug(
                f'Cannot find UTXO for address {address} ({cls.symbols[0]})')
            return
        unspent = data.get('txrefs', [])

        for output in unspent:
            output['value'] = int(output['value'])

        unspent = sorted(unspent, key=lambda k: k['value'], reverse=True)

        utxo = []
        total = 0

        for output in unspent:
            value = from_base_units(output['value'])
            utxo.append(
                Utxo(
                    tx_id=output['tx_hash'],
                    vout=output['tx_output_n'],
                    value=value,
                    tx_script=output['script'],
                ))
            total += value
            if total > amount:
                return utxo

        logger.debug(f'Cannot find enough UTXO\'s. Found %.8f from %.8f.',
                     total, amount)
Exemple #8
0
def get_utxo_from_api(network: str,
                      address: str,
                      amount: float,
                      use_blockcypher: bool = False,
                      testnet: bool = False,
                      cryptoid_api_key: str = None) -> Optional[list]:
    from clove.network.bitcoin.utxo import Utxo

    if use_blockcypher:
        subnet = 'test3' if testnet else 'main'
        api_url = f'https://api.blockcypher.com/v1/{network}/{subnet}/addrs/{address}' \
                  f'?limit=2000&unspentOnly=true&includeScript=true&confirmations=6'
        unspent_key = 'txrefs'
        vout_key = 'tx_output_n'
    elif cryptoid_api_key is None:
        raise ValueError('API key for cryptoid is required to get UTXOs.')
    else:
        api_url = f'https://chainz.cryptoid.info/{network}/api.dws?q=unspent&key={cryptoid_api_key}&active={address}'
        unspent_key = 'unspent_outputs'
        vout_key = 'tx_ouput_n'

    data = clove_req_json(api_url)
    if data is None:
        logger.debug('Could not get UTXOs for address %s in %s network',
                     address, network)
        return

    unspent = data.get(unspent_key, [])

    for output in unspent:
        output['value'] = int(output['value'])

    unspent = sorted(unspent, key=lambda k: k['value'], reverse=True)

    utxo = []
    total = 0

    for output in unspent:
        value = from_base_units(output['value'])
        utxo.append(
            Utxo(
                tx_id=output['tx_hash'],
                vout=output[vout_key],
                value=value,
                tx_script=output['script'],
            ))
        total += value
        if total > amount:
            return utxo

    logger.debug(f'Cannot find enough UTXO\'s. Found %.8f from %.8f.', total,
                 amount)
Exemple #9
0
    def get_balance(cls, wallet_address: str) -> float:
        '''
        Returns wallet balance without unconfirmed transactions.

        Args:
            wallet_address (str): wallet address

        Returns:
            float: amount converted from base units

        Example:
            >>> from clove.network import Ravencoin
            >>> r = Ravencoin()
            >>> r.get_balance('RM7w75BcC21LzxRe62jy8JhFYykRedqu8k')
            >>> 18.99
        '''
        wallet_utxo = clove_req_json(f'{cls.api_url}/addr/{wallet_address}/balance')
        if not wallet_utxo:
            return 0
        return from_base_units(wallet_utxo)
Exemple #10
0
    def get_fee(cls) -> Optional[float]:
        '''
        Getting actual fee per kb

        Returns:
            float, None: actual fee per kb or None if eg. API is not responding

        Example:
            >>> from clove.network import BitcoinTestNet
            >>> network = BitcoinTestNet()
            >>> network.get_fee()
            0.00024538
        '''
        response = clove_req_json(cls.blockcypher_url())
        fee = response.get('high_fee_per_kb')
        if not fee:
            logger.error(
                'Cannot find the right key (high_fee_per_kb) while getting fee in blockcypher.'
            )
            return
        return from_base_units(fee)
Exemple #11
0
    def get_utxo(cls, address, amount):
        data = clove_req_json(f'{cls.api_url}/addrs/{address}/utxo')
        unspent = sorted(data, key=lambda k: k['satoshis'], reverse=True)

        utxo = []
        total = 0

        for output in unspent:
            value = from_base_units(output['satoshis'])
            utxo.append(
                Utxo(
                    tx_id=output['txid'],
                    vout=output['vout'],
                    value=value,
                    tx_script=output['scriptPubKey'],
                )
            )
            total += value
            if total > amount:
                return utxo

        logger.debug(f'Cannot find enough UTXO\'s. Found %.8f from %.8f.', total, amount)
Exemple #12
0
    def get_balance(cls, wallet_address: str) -> Optional[float]:
        '''
        Returns wallet balance without unconfirmed transactions.

        Args:
            wallet_address (str): wallet address

        Returns:
            float, None: account balance converted from base units or None if something went wrong

        Example:
            >>> from clove.network import BitcoinTestNet
            >>> network = BitcoinTestNet()
            >>> network.get_balance('msJ2ucZ2NDhpVzsiNE5mGUFzqFDggjBVTM')
            4.22188744
        '''
        data = clove_req_json(
            f'{cls.blockcypher_url()}/addrs/{wallet_address}/balance')
        if data is None:
            logger.error('Could not get details for address %s in %s network',
                         wallet_address, cls.symbols[0])
            return
        return from_base_units(data['balance'] or data['unconfirmed_balance'])
Exemple #13
0
    def get_utxo(cls, address, amount):
        data = clove_req_json(
            f'https://mona.chainseeker.info/api/v1/utxos/{address}')
        unspent = sorted(data, key=lambda k: k['value'], reverse=True)

        utxo = []
        total = 0

        for output in unspent:
            value = from_base_units(output['value'])
            utxo.append(
                Utxo(
                    tx_id=output['txid'],
                    vout=output['vout'],
                    value=value,
                    tx_script=output['scriptPubKey']['hex'],
                ))
            total += value
            if total > amount:
                return utxo

        logger.debug(f'Cannot find enough UTXO\'s. Found %.8f from %.8f.',
                     total, amount)
Exemple #14
0
    def __init__(
        self,
        network,
        contract: str,
        raw_transaction: Optional[str]=None,
        transaction_address: Optional[str]=None
    ):

        if not raw_transaction and not transaction_address:
            raise ValueError('Provide raw_transaction or transaction_address argument.')

        self.network = network
        self.symbol = self.network.default_symbol
        self.contract = contract
        self.tx = None
        self.vout = None
        self.confirmations = None
        self.tx_address = transaction_address
        if raw_transaction:
            self.tx = self.network.deserialize_raw_transaction(raw_transaction)
            try:
                self.vout = self.tx.vout[0]
            except IndexError:
                raise ValueError('Given transaction has no outputs.')
        else:
            tx_json = get_transaction(network.default_symbol, transaction_address, network.is_test_network())
            if not tx_json:
                raise ValueError('No transaction found under given address.')
            if 'hex' in tx_json:
                # transaction from blockcypher or raven explorer
                self.tx = self.network.deserialize_raw_transaction(tx_json['hex'])
                self.vout = self.tx.vout[0]
            else:
                # transaction from cryptoid
                incorrect_cscript = script.CScript.fromhex(tx_json['outputs'][0]['script'])
                correct_cscript = script.CScript([script.OP_HASH160, list(incorrect_cscript)[2], script.OP_EQUAL])
                nValue = to_base_units(tx_json['outputs'][0]['amount'])
                self.vout = CTxOut(nValue, correct_cscript)

            if 'confirmations' in tx_json:
                self.confirmations = tx_json['confirmations']
            elif 'block_height' in tx_json:
                self.confirmations = self.network.latest_block - tx_json['block_height']
            elif 'block' in tx_json:
                self.confirmations = self.network.latest_block - tx_json['block']

        if not self.vout:
            raise ValueError('Given transaction has no outputs.')

        contract_tx_out = self.vout
        contract_script = script.CScript.fromhex(self.contract)
        script_pub_key = contract_script.to_p2sh_scriptPubKey()
        valid_p2sh = script_pub_key == contract_tx_out.scriptPubKey
        self.address = str(CBitcoinAddress.from_scriptPubKey(script_pub_key))
        self.balance = get_balance(self.network, self.address)

        script_ops = list(contract_script)
        if valid_p2sh and self.is_valid_contract_script(script_ops):
            self.recipient_address = str(P2PKHBitcoinAddress.from_bytes(script_ops[6]))
            self.refund_address = str(P2PKHBitcoinAddress.from_bytes(script_ops[13]))
            self.locktime_timestamp = int.from_bytes(script_ops[8], byteorder='little')
            self.locktime = datetime.utcfromtimestamp(self.locktime_timestamp)
            self.secret_hash = b2x(script_ops[2])
            self.value = from_base_units(contract_tx_out.nValue)
        else:
            raise ValueError('Given transaction is not a valid contract.')
Exemple #15
0
def test_from_base_units(satoshi_value):
    btc_value = from_base_units(satoshi_value)

    assert isinstance(btc_value, float)
    assert btc_value == satoshi_value / COIN
Exemple #16
0
 def get_balance(wallet_address: str) -> float:
     wallet_utxo = clove_req_json(
         f'https://mona.chainseeker.info/api/v1/utxos/{wallet_address}')
     if not wallet_utxo:
         return 0
     return from_base_units(sum([utxo['value'] for utxo in wallet_utxo]))