# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys, time, datetime, re, threading
-from electrum.i18n import _, set_language
-from electrum.util import print_error, print_msg
+from electrum_nvc.i18n import _, set_language
+from electrum_nvc.util import print_error, print_msg
import os.path, json, ast, traceback
import webbrowser
import shutil
from PyQt4.QtCore import *
import PyQt4.QtCore as QtCore
-from electrum.bitcoin import MIN_RELAY_TX_FEE, is_valid
-from electrum.plugins import run_hook
+from electrum_nvc.bitcoin import MIN_RELAY_TX_FEE, is_valid
+from electrum_nvc.plugins import run_hook
import icons_rc
-from electrum.util import format_satoshis
-from electrum import Transaction
-from electrum import mnemonic
-from electrum import util, bitcoin, commands, Interface, Wallet
-from electrum import SimpleConfig, Wallet, WalletStorage
+from electrum_nvc.util import format_satoshis
+from electrum_nvc import Transaction
+from electrum_nvc import mnemonic
+from electrum_nvc import util, bitcoin, commands, Interface, Wallet
+from electrum_nvc import SimpleConfig, Wallet, WalletStorage
+from electrum_nvc import Imported_Wallet
from amountedit import AmountEdit, BTCAmountEdit, MyLineEdit
from network_dialog import NetworkDialog
PR_ERROR = 4 # could not parse
-from electrum import ELECTRUM_VERSION
+from electrum_nvc import ELECTRUM_VERSION
import re
-from util import *
+from util import MyTreeWidget, HelpButton, EnterButton, line_dialog, text_dialog, ok_cancel_buttons, close_button, WaitingDialog
def format_status(x):
self.create_status_bar()
self.need_update = threading.Event()
- self.decimal_point = config.get('decimal_point', 5)
+ self.decimal_point = config.get('decimal_point', 6)
self.num_zeros = int(config.get('num_zeros',0))
self.invoices = {}
def load_wallet(self, wallet):
- import electrum
+ import electrum_nvc
self.wallet = wallet
self.update_wallet_format()
import installwizard
wallet_folder = os.path.dirname(self.wallet.storage.path)
- filename = unicode( QFileDialog.getSaveFileName(self, _('Enter a new file name'), wallet_folder) )
+ i = 1
+ while True:
+ filename = "wallet_%d"%i
+ if filename in os.listdir(wallet_folder):
+ i += 1
+ else:
+ break
+
+ filename = line_dialog(self, _('New Wallet'), _('Enter file name') + ':', _('OK'), filename)
if not filename:
return
- filename = os.path.join(wallet_folder, filename)
- storage = WalletStorage({'wallet_path': filename})
+ full_path = os.path.join(wallet_folder, filename)
+ storage = WalletStorage({'wallet_path': full_path})
if storage.file_exists:
QMessageBox.critical(None, "Error", _("File exists"))
return
raw_transaction_menu.addAction(_("&From file"), self.do_process_from_file)
raw_transaction_menu.addAction(_("&From text"), self.do_process_from_text)
raw_transaction_menu.addAction(_("&From the blockchain"), self.do_process_from_txid)
+ raw_transaction_menu.addAction(_("&From QR code"), self.read_tx_from_qrcode)
self.raw_transaction_menu = raw_transaction_menu
help_menu = menubar.addMenu(_("&Help"))
self.setMenuBar(menubar)
def show_about(self):
- QMessageBox.about(self, "Electrum",
- _("Version")+" %s" % (self.wallet.electrum_version) + "\n\n" + _("Electrum's focus is speed, with low resource usage and simplifying Bitcoin. You do not need to perform regular backups, because your wallet can be recovered from a secret phrase that you can memorize or write on paper. Startup times are instant because it operates in conjunction with high-performance servers that handle the most complicated parts of the Bitcoin system."))
+ QMessageBox.about(self, "Electrum-NVC",
+ _("Version")+" %s" % (self.wallet.electrum_version) + "\n\n" + _("Electrum's focus is speed, with low resource usage and simplifying Bitcoin. You do not need to perform regular backups, because your wallet can be recovered from a secret phrase that you can memorize or write on paper. Startup times are instant because it operates in conjunction with high-performance servers that handle the most complicated parts of the Novacoin system."))
def show_report_bug(self):
QMessageBox.information(self, "Electrum - " + _("Reporting Bugs"),
self.notify(_("New transaction received. %(amount)s %(unit)s") % { 'amount' : self.format_amount(v), 'unit' : self.base_unit()})
def notify(self, message):
- self.tray.showMessage("Electrum", message, QSystemTrayIcon.Information, 20000)
+ self.tray.showMessage("Electrum-NVC", message, QSystemTrayIcon.Information, 20000)
def base_unit(self):
- assert self.decimal_point in [5,8]
- return "BTC" if self.decimal_point == 8 else "mBTC"
-
+ assert self.decimal_point in [2, 3, 6]
+ if self.decimal_point == 2:
+ return 'bits'
+ if self.decimal_point == 3:
+ return 'mNVC'
+ if self.decimal_point == 6:
+ return 'NVC'
+ raise Exception('Unknown base unit')
def update_status(self):
if self.network is None or not self.network.is_running():
def create_history_menu(self, position):
self.history_list.selectedIndexes()
item = self.history_list.currentItem()
- be = self.config.get('block_explorer', 'Blockchain.info')
- if be == 'Blockchain.info':
- block_explorer = 'https://blockchain.info/tx/'
- elif be == 'Blockr.io':
- block_explorer = 'https://blockr.io/tx/info/'
- elif be == 'Insight.is':
- block_explorer = 'http://live.insight.is/tx/'
+ be = self.config.get('block_explorer', 'explorer.novaco.in')
+ if be == 'explorer.novaco.in':
+ block_explorer = 'https://explorer.novaco.in/tx/'
+ elif be == 'novacoin.su':
+ block_explorer = 'http://novacoin.su/tx/'
if not item: return
+
tx_hash = str(item.data(0, Qt.UserRole).toString())
if not tx_hash: return
menu = QMenu()
menu.addAction(_("Copy ID to Clipboard"), lambda: self.app.clipboard().setText(tx_hash))
menu.addAction(_("Details"), lambda: self.show_transaction(self.wallet.transactions.get(tx_hash)))
menu.addAction(_("Edit description"), lambda: self.tx_label_clicked(item,2))
- menu.addAction(_("View on block explorer"), lambda: webbrowser.open(block_explorer + tx_hash))
+ menu.addAction(_("View on explorer"), lambda: webbrowser.open(block_explorer + tx_hash))
menu.exec_(self.contacts_list.viewport().mapToGlobal(position))
self.save_request_button.clicked.connect(self.save_payment_request)
grid.addWidget(self.save_request_button, 3, 1)
clear_button = QPushButton(_('New'))
- clear_button.clicked.connect(self.clear_receive_tab)
+ clear_button.clicked.connect(self.new_receive_address)
grid.addWidget(clear_button, 3, 2)
grid.setRowStretch(4, 1)
self.wallet.storage.put('receive_requests', self.receive_requests)
self.update_receive_tab()
+ def new_receive_address(self):
+ domain = self.wallet.get_account_addresses(self.current_account, include_change=False)
+ for addr in domain:
+ if not self.wallet.history.get(addr) and addr not in self.receive_requests.keys():
+ break
+ else:
+ if isinstance(self.wallet, Imported_Wallet):
+ self.show_message(_('No more addresses in your wallet.'))
+ return
+ if not self.question(_("Warning: The next address will not be recovered automatically if you restore your wallet from seed; you may need to add it manually.\n\nThis occurs because you have too many unused addresses in your wallet. To avoid this situation, use the existing addresses first.\n\nCreate anyway?")):
+ return
+ addr = self.wallet.create_new_address(self.current_account, False)
+ self.receive_address_e.setText(addr)
+ self.receive_message_e.setText('')
+ self.receive_amount_e.setAmount(None)
+
def clear_receive_tab(self):
self.receive_requests = self.wallet.storage.get('receive_requests',{})
domain = self.wallet.get_account_addresses(self.current_account, include_change=False)
for addr in domain:
- if not self.wallet.address_is_old(addr) and addr not in self.receive_requests.keys():
+ if not self.wallet.history.get(addr) and addr not in self.receive_requests.keys():
break
else:
- addr = ""
+ addr = ''
self.receive_address_e.setText(addr)
self.receive_message_e.setText('')
self.receive_amount_e.setAmount(None)
from paytoedit import PayToEdit
self.amount_e = BTCAmountEdit(self.get_decimal_point)
self.payto_e = PayToEdit(self)
- self.payto_help = HelpButton(_('Recipient of the funds.') + '\n\n' + _('You may enter a Bitcoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Bitcoin address)'))
+ self.payto_help = HelpButton(_('Recipient of the funds.') + '\n\n' + _('You may enter a Novacoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Novacoin address)'))
grid.addWidget(QLabel(_('Pay to')), 1, 0)
grid.addWidget(self.payto_e, 1, 1, 1, 3)
grid.addWidget(self.payto_help, 1, 4)
grid.addWidget(QLabel(_('Fee')), 5, 0)
grid.addWidget(self.fee_e, 5, 1, 1, 2)
grid.addWidget(HelpButton(
- _('Bitcoin transactions are in general not free. A transaction fee is paid by the sender of the funds.') + '\n\n'\
+ _('Novacoin transactions are in general not free. A transaction fee is paid by the sender of the funds.') + '\n\n'\
+ _('The amount of fee can be decided freely by the sender. However, transactions with low fees take more time to be processed.') + '\n\n'\
+ _('A suggested fee is automatically added to this field. You may override it. The suggested fee increases with the size of the transaction.')), 5, 3)
amount = self.amount_e.get_amount()
fee = self.fee_e.get_amount()
+ outputs = self.payto_e.get_outputs()
+
+ if not is_fee:
+ fee = None
- if not is_fee: fee = None
if amount is None:
self.fee_e.setAmount(None)
- return
- # assume that there will be 2 outputs (one for change)
- inputs, total, fee = self.wallet.choose_tx_inputs(amount, fee, 2, coins = self.get_coins())
- if not is_fee:
- self.fee_e.setAmount(fee)
- if inputs:
+ not_enough_funds = False
+ else:
+ inputs, total, fee = self.wallet.choose_tx_inputs(amount, fee, len(outputs), coins = self.get_coins())
+ not_enough_funds = len(inputs) == 0
+ if not is_fee:
+ self.fee_e.setAmount(fee)
+
+ if not not_enough_funds:
palette = QPalette()
palette.setColor(self.amount_e.foregroundRole(), QColor('black'))
text = ""
QMessageBox.warning(self, _('Error'), _('No outputs'), _('OK'))
return
- for addr, x in outputs:
- if addr is None or not bitcoin.is_address(addr):
- QMessageBox.warning(self, _('Error'), _('Invalid Bitcoin Address'), _('OK'))
+ for type, addr, amount in outputs:
+ if addr is None:
+ QMessageBox.warning(self, _('Error'), _('Novacoin Address is None'), _('OK'))
+ return
+ if type == 'op_return':
+ continue
+ if type == 'address' and not bitcoin.is_address(addr):
+ QMessageBox.warning(self, _('Error'), _('Invalid Novacoin Address'), _('OK'))
return
- if x is None:
+ if amount is None:
QMessageBox.warning(self, _('Error'), _('Invalid Amount'), _('OK'))
return
- amount = sum(map(lambda x:x[1], outputs))
+ amount = sum(map(lambda x:x[2], outputs))
fee = self.fee_e.get_amount()
if fee is None:
QMessageBox.warning(self, _('Error'), _('Invalid Fee'), _('OK'))
return
- confirm_amount = self.config.get('confirm_amount', 100000000)
+ confirm_amount = self.config.get('confirm_amount', 10000)
if amount >= confirm_amount:
- o = '\n'.join(map(lambda x:x[0], outputs))
+ o = '\n'.join(map(lambda x:x[1], outputs))
if not self.question(_("send %(amount)s to %(address)s?")%{ 'amount' : self.format_amount(amount) + ' '+ self.base_unit(), 'address' : o}):
return
- confirm_fee = self.config.get('confirm_fee', 100000)
+ confirm_fee = self.config.get('confirm_fee', 10000)
if fee >= confirm_fee:
if not self.question(_("The fee for this transaction seems unusually high.\nAre you really sure you want to pay %(fee)s in fees?")%{ 'fee' : self.format_amount(fee) + ' '+ self.base_unit()}):
return
# sign the tx
def sign_thread():
+ if self.wallet.is_watching_only():
+ return tx
keypairs = {}
try:
self.wallet.add_keypairs(tx, keypairs, password)
self.wallet.sign_transaction(tx, keypairs, password)
except Exception as e:
+ traceback.print_exc(file=sys.stdout)
tx.error = str(e)
return tx
try:
address, amount, label, message, request_url = util.parse_URI(URI)
except Exception as e:
- QMessageBox.warning(self, _('Error'), _('Invalid bitcoin URI:') + '\n' + str(e), _('OK'))
+ QMessageBox.warning(self, _('Error'), _('Invalid novacoin URI:') + '\n' + str(e), _('OK'))
return
self.tabs.setCurrentIndex(1)
self.amount_e.setAmount(amount)
return
- from electrum import paymentrequest
+ from electrum_nvc import paymentrequest
def payment_request():
self.payment_request = paymentrequest.PaymentRequest(self.config)
self.payment_request.read(request_url)
def create_invoices_tab(self):
- l, w = self.create_list_tab([_('Requestor'), _('Memo'),_('Amount'), _('Status')])
+ l, w = self.create_list_tab([_('Requestor'), _('Memo'), _('Date'), _('Amount'), _('Status')])
l.setColumnWidth(0, 150)
+ l.setColumnWidth(2, 150)
+ l.setColumnWidth(3, 150)
h = l.header()
h.setStretchLastSection(False)
h.setResizeMode(1, QHeaderView.Stretch)
invoices = self.wallet.storage.get('invoices', {})
l = self.invoices_list
l.clear()
- for key, value in invoices.items():
- try:
- domain, memo, amount, expiration_date, status, tx_hash = value
- except:
- invoices.pop(key)
- continue
+ for key, value in sorted(invoices.items(), key=lambda x: -x[1][3]):
+ domain, memo, amount, expiration_date, status, tx_hash = value
if status == PR_UNPAID and expiration_date and expiration_date < time.time():
status = PR_EXPIRED
- item = QTreeWidgetItem( [ domain, memo, self.format_amount(amount), format_status(status)] )
+ date_str = datetime.datetime.fromtimestamp(expiration_date).isoformat(' ')[:-3]
+ item = QTreeWidgetItem( [ domain, memo, date_str, self.format_amount(amount, whitespaces=True), format_status(status)] )
+ item.setData(0, 32, key)
+ item.setFont(0, QFont(MONOSPACE_FONT))
+ item.setFont(3, QFont(MONOSPACE_FONT))
l.addTopLevelItem(item)
-
l.setCurrentItem(l.topLevelItem(0))
-
-
def delete_imported_key(self, addr):
if self.question(_("Do you want to remove")+" %s "%addr +_("from your wallet?")):
self.wallet.delete_imported_key(addr)
payto_addr = item.data(0,33).toString()
menu.addAction(_("Copy to Clipboard"), lambda: self.app.clipboard().setText(addr))
menu.addAction(_("Pay to"), lambda: self.payto(payto_addr))
- menu.addAction(_("QR code"), lambda: self.show_qrcode("bitcoin:" + addr, _("Address")))
+ menu.addAction(_("QR code"), lambda: self.show_qrcode("novacoin:" + addr, _("Address")))
if is_editable:
menu.addAction(_("Edit label"), lambda: self.edit_label(False))
menu.addAction(_("Delete"), lambda: self.delete_contact(addr))
self.update_invoices_tab()
def show_invoice(self, key):
- from electrum.paymentrequest import PaymentRequest
+ from electrum_nvc.paymentrequest import PaymentRequest
domain, memo, value, expiration, status, tx_hash = self.invoices[key]
pr = PaymentRequest(self.config)
pr.read_file(key)
pr.domain = domain
pr.verify()
- self.show_pr_details(pr)
+ self.show_pr_details(pr, tx_hash)
- def show_pr_details(self, pr):
+ def show_pr_details(self, pr, tx_hash=None):
msg = 'Domain: ' + pr.domain
msg += '\nStatus: ' + pr.get_status()
msg += '\nMemo: ' + pr.get_memo()
msg += '\nPayment URL: ' + pr.payment_url
- msg += '\n\nOutputs:\n' + '\n'.join(map(lambda x: x[0] + ' ' + self.format_amount(x[1])+ self.base_unit(), pr.get_outputs()))
+ msg += '\n\nOutputs:\n' + '\n'.join(map(lambda x: x[1] + ' ' + self.format_amount(x[2])+ self.base_unit(), pr.get_outputs()))
+ if tx_hash:
+ msg += '\n\nTransaction ID: ' + tx_hash
QMessageBox.information(self, 'Invoice', msg , 'OK')
def do_pay_invoice(self, key):
- from electrum.paymentrequest import PaymentRequest
+ from electrum_nvc.paymentrequest import PaymentRequest
domain, memo, value, expiration, status, tx_hash = self.invoices[key]
pr = PaymentRequest(self.config)
pr.read_file(key)
item = self.invoices_list.itemAt(position)
if not item:
return
- k = self.invoices_list.indexOfTopLevelItem(item)
- key = self.invoices.keys()[k]
+ key = str(item.data(0, 32).toString())
domain, memo, value, expiration, status, tx_hash = self.invoices[key]
menu = QMenu()
menu.addAction(_("Details"), lambda: self.show_invoice(key))
vbox.addWidget(QLabel(_('Account name')+':'))
e = QLineEdit()
vbox.addWidget(e)
- msg = _("Note: Newly created accounts are 'pending' until they receive bitcoins.") + " " \
+ msg = _("Note: Newly created accounts are 'pending' until they receive novacoins.") + " " \
+ _("You will need to wait for 2 confirmations until the correct balance is displayed and more addresses are created for that account.")
l = QLabel(msg)
l.setWordWrap(True)
self.wallet.create_pending_account(name, password)
self.update_address_tab()
- self.tabs.setCurrentIndex(2)
+ self.tabs.setCurrentIndex(3)
pubkey_e = QLineEdit()
if address:
- pubkey = self.wallet.getpubkeys(address)[0]
+ pubkey = self.wallet.get_public_keys(address)[0]
pubkey_e.setText(pubkey)
layout.addWidget(QLabel(_('Public key')), 2, 0)
layout.addWidget(pubkey_e, 2, 1)
if is_hex:
try:
- return Transaction(txt)
+ return Transaction.deserialize(txt)
except:
traceback.print_exc(file=sys.stdout)
QMessageBox.critical(None, _("Unable to parse transaction"), _("Electrum was unable to parse your transaction"))
try:
tx_dict = json.loads(str(txt))
assert "hex" in tx_dict.keys()
- tx = Transaction(tx_dict["hex"])
+ tx = Transaction.deserialize(tx_dict["hex"])
#if tx_dict.has_key("input_info"):
# input_info = json.loads(tx_dict['input_info'])
# tx.add_input_info(input_info)
QMessageBox.critical(None, _("Unable to parse transaction"), _("Electrum was unable to parse your transaction"))
+ def read_tx_from_qrcode(self):
+ data = run_hook('scan_qr_hook')
+ if not data:
+ return
+ # transactions are binary, but qrcode seems to return utf8...
+ z = data.decode('utf8')
+ s = ''
+ for b in z:
+ s += chr(ord(b))
+ data = s.encode('hex')
+ tx = self.tx_from_text(data)
+ if not tx:
+ return
+ self.show_transaction(tx)
+
def read_tx_from_file(self):
fileName = self.getOpenFileName(_("Select your transaction file"), "*.txn")
self.show_transaction(tx)
def do_process_from_txid(self):
- from electrum import transaction
+ from electrum_nvc import transaction
txid, ok = QInputDialog.getText(self, _('Lookup transaction'), _('Transaction ID') + ':')
if ok and txid:
r = self.network.synchronous_get([ ('blockchain.transaction.get',[str(txid)]) ])[0]
if r:
- tx = transaction.Transaction(r)
+ tx = transaction.Transaction.deserialize(r)
if tx:
self.show_transaction(tx)
else:
try:
for position, row in enumerate(csvReader):
address = row[0]
- if not is_valid(address):
+ if not is_address(address):
errors.append((position, address))
continue
amount = Decimal(row[1])
- amount = int(100000000*amount)
- outputs.append((address, amount))
+ amount = int(1000000*amount)
+ outputs.append(('address', address, amount))
except (ValueError, IOError, os.error), reason:
QMessageBox.critical(None, _("Unable to read file or no transaction found"), _("Electrum was unable to open your transaction file") + "\n" + str(reason))
return
d.setMinimumSize(400, 200)
vbox = QVBoxLayout(d)
- defaultname = os.path.expanduser('~/electrum-history.csv')
+ defaultname = os.path.expanduser('~/electrum-nvc-history.csv')
select_msg = _('Select file to export your wallet transactions to')
hbox, filename_e, csv_button = filename_field(self, self.config, defaultname, select_msg)
lang_label=QLabel(_('Language') + ':')
grid.addWidget(lang_label, 1, 0)
lang_combo = QComboBox()
- from electrum.i18n import languages
+ from electrum_nvc.i18n import languages
lang_combo.addItems(languages.values())
try:
index = languages.keys().index(self.config.get("language",''))
fee_e.setAmount(self.wallet.fee)
grid.addWidget(fee_e, 2, 1)
msg = _('Fee per kilobyte of transaction.') + '\n' \
- + _('Recommended value') + ': ' + self.format_amount(10000) + ' ' + self.base_unit()
+ + _('Recommended value') + ': ' + self.format_amount(1000) + ' ' + self.base_unit()
grid.addWidget(HelpButton(msg), 2, 2)
if not self.config.is_modifiable('fee_per_kb'):
for w in [fee_e, fee_label]: w.setEnabled(False)
- units = ['BTC', 'mBTC']
+ units = ['NVC', 'mNVC', 'bits']
unit_label = QLabel(_('Base unit') + ':')
grid.addWidget(unit_label, 3, 0)
unit_combo = QComboBox()
unit_combo.setCurrentIndex(units.index(self.base_unit()))
grid.addWidget(unit_combo, 3, 1)
grid.addWidget(HelpButton(_('Base unit of your wallet.')\
- + '\n1BTC=1000mBTC.\n' \
+ + '\n1NVC=1000mNVC.\n' \
+ _(' These settings affects the fields in the Send tab')+' '), 3, 2)
usechange_cb = QCheckBox(_('Use change addresses'))
grid.addWidget(HelpButton(_('Using change addresses makes it more difficult for other people to track your transactions.')+' '), 4, 2)
if not self.config.is_modifiable('use_change'): usechange_cb.setEnabled(False)
- block_explorers = ['Blockchain.info', 'Blockr.io', 'Insight.is']
+ block_explorers = ['explorer.novaco.in', 'novacoin.su']
block_ex_label = QLabel(_('Online Block Explorer') + ':')
grid.addWidget(block_ex_label, 5, 0)
block_ex_combo = QComboBox()
block_ex_combo.addItems(block_explorers)
- block_ex_combo.setCurrentIndex(block_explorers.index(self.config.get('block_explorer', 'Blockchain.info')))
+ block_ex_combo.setCurrentIndex(block_explorers.index(self.config.get('block_explorer', 'explorer.novaco.in')))
grid.addWidget(block_ex_combo, 5, 1)
grid.addWidget(HelpButton(_('Choose which online block explorer to use for functions that open a web browser')+' '), 5, 2)
unit_result = units[unit_combo.currentIndex()]
if self.base_unit() != unit_result:
- self.decimal_point = 8 if unit_result == 'BTC' else 5
+ if unit_result == 'NVC':
+ self.decimal_point = 6
+ elif unit_result == 'mNVC':
+ self.decimal_point = 3
+ elif unit_result == 'bits':
+ self.decimal_point = 2
+ else:
+ raise Exception('Unknown base unit')
self.config.set_key('decimal_point', self.decimal_point, True)
self.update_history_tab()
self.update_status()
def plugins_dialog(self):
- from electrum.plugins import plugins
+ from electrum_nvc.plugins import plugins
d = QDialog(self)
d.setWindowTitle(_('Electrum Plugins'))