def btnSendClick(self):
        """
        Sends funds to Dash address specified by user.
        """
        utxos = self.table_model.getSelectedUtxos()
        if len(utxos):
            address = self.edtDestAddress.text()
            if address:
                if not self.main_ui.connectHardwareWallet():
                    return

                bip32_to_address = {
                }  # for saving addresses read from HW by BIP32 path

                # check if user selected masternode collateral transaction; if so display warning
                # also check if UTXO dash address matches address of BIP32 path in HW
                for utxo in utxos:
                    if utxo['collateral']:
                        if self.queryDlg(
                                "Warning: you are going to transfer Masternode's collateral (1000 Dash) transaction "
                                "output. Proceeding will result in broken Masternode.\n\n"
                                "Do you really want to continue?",
                                buttons=QMessageBox.Yes | QMessageBox.Cancel,
                                default_button=QMessageBox.Cancel,
                                icon=QMessageBox.Warning
                        ) == QMessageBox.Cancel:
                            return
                    bip32_path = utxo.get('bip32_path', None)
                    if not bip32_path:
                        self.errorMsg(
                            'No BIP32 path for UTXO: %s. Cannot continue.' %
                            utxo['txid'])
                        return

                    addr_hw = bip32_to_address.get(bip32_path, None)
                    if not addr_hw:
                        address_n = self.main_ui.hw_client.expand_path(
                            bip32_path)
                        addr_hw = hw_get_address(self.main_ui.hw_client,
                                                 address_n)
                        bip32_to_address[bip32_path] = addr_hw
                    if addr_hw != utxo['address']:
                        self.errorMsg(
                            "Current Dash address from %s's path %s (%s) doesn't match address of funds "
                            "being sent (%s).\n\nCannot continue." %
                            (self.main_ui.getHwName(), bip32_path, addr_hw,
                             utxo['address']))
                        return

                try:
                    if self.dashd_intf.validateaddress(address).get(
                            'isvalid', False):
                        fee = self.edtTxFee.value() * 1e8
                        serialized_tx, amount_to_send = prepare_transfer_tx(
                            self.main_ui, utxos, address, fee)
                        tx_hex = serialized_tx.hex()
                        if len(tx_hex) > 90000:
                            self.errorMsg(
                                "Transaction's length exceeds 90000 bytes. Select less utxo's and try again."
                            )
                        else:
                            if self.queryDlg(
                                    'Broadcast signed transaction?\n\n'
                                    'Destination address: %s\n'
                                    'Amount to send: %s Dash\nFee: %s Dash\n'
                                    'Size: %d bytes' %
                                (address, str(round(amount_to_send / 1e8, 8)),
                                 str(round(fee / 1e8, 8)), len(tx_hex) / 2),
                                    buttons=QMessageBox.Yes
                                    | QMessageBox.Cancel,
                                    default_button=QMessageBox.Yes
                            ) == QMessageBox.Yes:

                                decoded_tx = self.dashd_intf.decoderawtransaction(
                                    tx_hex)
                                txid = self.dashd_intf.sendrawtransaction(
                                    tx_hex)
                                if txid:
                                    self.infoMsg('Transaction sent. ID: ' +
                                                 txid)
                                else:
                                    self.errorMsg(
                                        'Problem with sending transaction: no txid returned'
                                    )
                    else:
                        self.errorMsg(
                            'Invalid destination Dash address (%s).' % address)
                except Exception as e:
                    self.errorMsg(str(e))
            else:
                self.errorMsg('Missing destination Dash address.')
        else:
            self.errorMsg('No utxo to send.')
    def on_btnSend_clicked(self):
        """
        Sends funds to GoByte address specified by user.
        """

        amount, utxos = self.get_selected_utxos()
        if len(utxos):
            try:
                if not self.main_ui.connect_hardware_wallet():
                    return
            except HardwareWalletCancelException:
                return

            bip32_to_address = {}  # for saving addresses read from HW by BIP32 path
            total_satoshis = 0
            coinbase_locked_exist = False

            # verify if:
            #  - utxo is the masternode collateral transation
            #  - the utxo GoByte (signing) address matches the hardware wallet address for a given path
            for utxo_idx, utxo in enumerate(utxos):
                total_satoshis += utxo['satoshis']
                logging.info(f'UTXO satosis: {utxo["satoshis"]}')
                if utxo['collateral']:
                    if self.queryDlg(
                            "Warning: you are going to transfer masternode's collateral (1000 GoByte) transaction "
                            "output. Proceeding will result in broken masternode.\n\n"
                            "Do you really want to continue?",
                            buttons=QMessageBox.Yes | QMessageBox.Cancel,
                            default_button=QMessageBox.Cancel, icon=QMessageBox.Warning) == QMessageBox.Cancel:
                        return
                if utxo['coinbase_locked']:
                    coinbase_locked_exist = True

                bip32_path = utxo.get('bip32_path', None)
                if not bip32_path:
                    self.errorMsg('No BIP32 path for UTXO: %s. Cannot continue.' % utxo['txid'])
                    return

                addr_hw = bip32_to_address.get(bip32_path, None)
                if not addr_hw:
                    addr_hw = get_address(self.main_ui.hw_session, bip32_path)
                    bip32_to_address[bip32_path] = addr_hw
                if addr_hw != utxo['address']:
                    self.errorMsg("<html style=\"font-weight:normal\">GoByte address inconsistency between UTXO (%d) and HW path: %s.<br><br>"
                                 "<b>HW address</b>: %s<br>"
                                 "<b>UTXO address</b>: %s<br><br>"
                                 "Cannot continue.</html>" %
                                  (utxo_idx+1, bip32_path, addr_hw, utxo['address']))
                    return

            if coinbase_locked_exist:
                if self.queryDlg(
                        "Warning: you have selected at least one coinbase transaction without the required number of "
                        "confirmations (100). Your transaction will probably be rejected by the network.\n\n"
                        "Do you really want to continue?",
                        buttons=QMessageBox.Yes | QMessageBox.Cancel,
                        default_button=QMessageBox.Cancel, icon=QMessageBox.Warning) == QMessageBox.Cancel:
                    return
            try:
                dest_data = self.wdg_dest_adresses.get_tx_destination_data()
                if dest_data:
                    total_satoshis_actual = 0
                    for dd in dest_data:
                        total_satoshis_actual += dd[1]
                        logging.info(f'dest amount: {dd[1]}')

                    fee = self.wdg_dest_adresses.get_tx_fee()
                    use_is = self.wdg_dest_adresses.get_use_instant_send()
                    logging.info(f'fee: {fee}')
                    if total_satoshis != total_satoshis_actual + fee:
                        logging.warning(f'total_satoshis ({total_satoshis}) != total_satoshis_real '
                                        f'({total_satoshis_actual}) + fee ({fee})')
                        logging.warning(f'total_satoshis_real + fee: {total_satoshis_actual + fee}')

                        if abs(total_satoshis - total_satoshis_actual - fee) > 10:
                            raise Exception('Data validation failure')

                    try:
                        serialized_tx, amount_to_send = prepare_transfer_tx(
                            self.main_ui.hw_session, utxos, dest_data, fee, self.rawtransactions)
                    except HardwareWalletCancelException:
                        # user cancelled the operations
                        hw_intf.cancel_hw_operation(self.main_ui.hw_session.hw_client)
                        return
                    except Exception:
                        logging.exception('Exception when preparing the transaction.')
                        raise

                    tx_hex = serialized_tx.hex()
                    logging.info('Raw signed transaction: ' + tx_hex)
                    if len(tx_hex) > 90000:
                        self.errorMsg("Transaction's length exceeds 90000 bytes. Select less UTXOs and try again.")
                    else:
                        tx_dlg = TransactionDlg(self, self.main_ui.config, self.gobyted_intf, tx_hex, use_is)
                        if tx_dlg.exec_():
                            amount, sel_utxos = self.get_selected_utxos()
                            if sel_utxos:
                                # mark and uncheck all spent utxox
                                for utxo_idx, utxo in enumerate(sel_utxos):
                                    utxo['spent_date'] = time.time()

                                self.table_model.beginResetModel()
                                self.table_model.endResetModel()
            except Exception as e:
                logging.exception('Unknown error occurred.')
                self.errorMsg(str(e))
        else:
            self.errorMsg('No UTXO to send.')
Ejemplo n.º 3
0
    def on_btnSend_clicked(self):
        """
        Sends funds to Dash address specified by user.
        """
        utxos = self.table_model.getSelectedUtxos()
        if len(utxos):
            address = self.edtDestAddress.text()
            if address:
                if not self.main_ui.connectHardwareWallet():
                    return

                bip32_to_address = {
                }  # for saving addresses read from HW by BIP32 path

                # check if user selected masternode collateral transaction; if so display warning
                # also check if UTXO dash address matches address of BIP32 path in HW
                for utxo_idx, utxo in enumerate(utxos):
                    if utxo['collateral']:
                        if self.queryDlg(
                                "Warning: you are going to transfer masternode's collateral (1000 Dash) transaction "
                                "output. Proceeding will result in broken masternode.\n\n"
                                "Do you really want to continue?",
                                buttons=QMessageBox.Yes | QMessageBox.Cancel,
                                default_button=QMessageBox.Cancel,
                                icon=QMessageBox.Warning
                        ) == QMessageBox.Cancel:
                            return
                    bip32_path = utxo.get('bip32_path', None)
                    if not bip32_path:
                        self.errorMsg(
                            'No BIP32 path for UTXO: %s. Cannot continue.' %
                            utxo['txid'])
                        return

                    addr_hw = bip32_to_address.get(bip32_path, None)
                    if not addr_hw:
                        addr_hw = get_address(self.main_ui, bip32_path)
                        bip32_to_address[bip32_path] = addr_hw
                    if addr_hw != utxo['address']:
                        self.errorMsg(
                            "Dash address inconsistency between UTXO (%d) and a HW's path: %s.\n\n"
                            "<b>HW address</b>: %s\n"
                            "<b>UTXO address</b>: %s\n\n"
                            "Cannot continue." % (utxo_idx + 1, bip32_path,
                                                  addr_hw, utxo['address']))
                        return

                try:
                    if self.dashd_intf.validateaddress(address).get(
                            'isvalid', False):
                        fee = self.edtTxFee.value() * 1e8

                        try:
                            serialized_tx, amount_to_send = prepare_transfer_tx(
                                self.main_ui, utxos, address, fee,
                                self.rawtransactions)
                        except Exception:
                            logging.exception(
                                'Exception when preparing the transaction.')
                            raise

                        tx_hex = serialized_tx.hex()
                        logging.info('Raw signed transaction: ' + tx_hex)
                        if len(tx_hex) > 90000:
                            self.errorMsg(
                                "Transaction's length exceeds 90000 bytes. Select less UTXOs and try again."
                            )
                        else:
                            if SCREENSHOT_MODE:
                                self.warnMsg('Inside screenshot mode')

                            if self.queryDlg(
                                    'Broadcast signed transaction?\n\n'
                                    '<b>Destination address</b>: %s\n'
                                    '<b>Amount to send</b>: %s Dash\n'
                                    '<b>Fee</b>: %s Dash\n'
                                    '<b>Size</b>: %d bytes' %
                                (address, str(round(amount_to_send / 1e8, 8)),
                                 str(round(fee / 1e8, 8)), len(tx_hex) / 2),
                                    buttons=QMessageBox.Yes
                                    | QMessageBox.Cancel,
                                    default_button=QMessageBox.Yes
                            ) == QMessageBox.Yes:

                                # decoded_tx = self.dashd_intf.decoderawtransaction(tx_hex)

                                if SCREENSHOT_MODE:
                                    txid = '2195aecd5575e37fedf30e6a7ae317c6ba3650a004dc7e901210ac454f61a2e8'
                                else:
                                    txid = self.dashd_intf.sendrawtransaction(
                                        tx_hex)

                                if txid:
                                    block_explorer = self.main_ui.config.block_explorer_tx
                                    if block_explorer:
                                        url = block_explorer.replace(
                                            '%TXID%', txid)
                                        message = 'Transaction sent. TX ID: <a href="%s">%s</a>' % (
                                            url, txid)
                                    else:
                                        message = 'Transaction sent. TX ID: %s' % txid

                                    logging.info('Sent transaction: ' + txid)
                                    self.infoMsg(message)
                                else:
                                    self.errorMsg(
                                        'Problem with sending transaction: no txid returned'
                                    )
                    else:
                        self.errorMsg(
                            'Invalid destination Dash address (%s).' % address)
                except Exception as e:
                    self.errorMsg(str(e))
            else:
                self.errorMsg('Missing destination Dash address.')
        else:
            self.errorMsg('No UTXO to send.')