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.')
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.')