show payment request details
This commit is contained in:
parent
0838b35058
commit
440f972fd3
|
@ -169,11 +169,7 @@ class ElectrumGui:
|
||||||
QMessageBox.warning(self.main_window, _('Error'), _('Invalid Amount'), _('OK'))
|
QMessageBox.warning(self.main_window, _('Error'), _('Invalid Amount'), _('OK'))
|
||||||
|
|
||||||
if request_url:
|
if request_url:
|
||||||
try:
|
from electrum import paymentrequest
|
||||||
from electrum import paymentrequest
|
|
||||||
except:
|
|
||||||
print "cannot import paymentrequest"
|
|
||||||
request_url = None
|
|
||||||
|
|
||||||
if not request_url:
|
if not request_url:
|
||||||
self.main_window.set_send(address, amount, label, message)
|
self.main_window.set_send(address, amount, label, message)
|
||||||
|
|
|
@ -933,7 +933,8 @@ class ElectrumWindow(QMainWindow):
|
||||||
self.update_invoices_tab()
|
self.update_invoices_tab()
|
||||||
|
|
||||||
self.payto_help.show()
|
self.payto_help.show()
|
||||||
self.payto_help.set_alt(pr.status)
|
self.payto_help.set_alt(lambda: self.show_pr_details(pr))
|
||||||
|
|
||||||
self.payto_e.setGreen()
|
self.payto_e.setGreen()
|
||||||
self.payto_e.setText(pr.domain)
|
self.payto_e.setText(pr.domain)
|
||||||
self.amount_e.setText(self.format_amount(pr.get_amount()))
|
self.amount_e.setText(self.format_amount(pr.get_amount()))
|
||||||
|
@ -973,7 +974,6 @@ class ElectrumWindow(QMainWindow):
|
||||||
h.show()
|
h.show()
|
||||||
|
|
||||||
self.payto_help.set_alt(None)
|
self.payto_help.set_alt(None)
|
||||||
|
|
||||||
self.set_pay_from([])
|
self.set_pay_from([])
|
||||||
self.update_status()
|
self.update_status()
|
||||||
|
|
||||||
|
@ -1211,18 +1211,36 @@ class ElectrumWindow(QMainWindow):
|
||||||
menu.exec_(self.contacts_list.viewport().mapToGlobal(position))
|
menu.exec_(self.contacts_list.viewport().mapToGlobal(position))
|
||||||
|
|
||||||
def delete_invoice(self, item):
|
def delete_invoice(self, item):
|
||||||
k = self.invoices_list.indexOfTopLevelItem(item)
|
|
||||||
key = self.invoices.keys()[k]
|
|
||||||
self.invoices.pop(key)
|
self.invoices.pop(key)
|
||||||
self.wallet.storage.put('invoices', self.invoices)
|
self.wallet.storage.put('invoices', self.invoices)
|
||||||
self.update_invoices_tab()
|
self.update_invoices_tab()
|
||||||
|
|
||||||
|
def show_invoice(self, key):
|
||||||
|
from electrum.paymentrequest import PaymentRequest
|
||||||
|
domain, value = self.invoices[key]
|
||||||
|
pr = PaymentRequest(self.config)
|
||||||
|
pr.read_file(key)
|
||||||
|
pr.domain = domain
|
||||||
|
pr.verify()
|
||||||
|
self.show_pr_details(pr)
|
||||||
|
|
||||||
|
def show_pr_details(self, pr):
|
||||||
|
msg = 'Domain: ' + pr.domain
|
||||||
|
msg += '\nStatus: ' + pr.get_status()
|
||||||
|
msg += '\nMemo: ' + pr.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()))
|
||||||
|
QMessageBox.information(self, 'Invoice', msg , 'OK')
|
||||||
|
|
||||||
def create_invoice_menu(self, position):
|
def create_invoice_menu(self, position):
|
||||||
item = self.invoices_list.itemAt(position)
|
item = self.invoices_list.itemAt(position)
|
||||||
if not item:
|
if not item:
|
||||||
return
|
return
|
||||||
|
k = self.invoices_list.indexOfTopLevelItem(item)
|
||||||
|
key = self.invoices.keys()[k]
|
||||||
menu = QMenu()
|
menu = QMenu()
|
||||||
menu.addAction(_("Delete"), lambda: self.delete_invoice(item))
|
menu.addAction(_("Details"), lambda: self.show_invoice(key))
|
||||||
|
menu.addAction(_("Delete"), lambda: self.delete_invoice(key))
|
||||||
menu.exec_(self.invoices_list.viewport().mapToGlobal(position))
|
menu.exec_(self.invoices_list.viewport().mapToGlobal(position))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -56,17 +56,19 @@ class HelpButton(QPushButton):
|
||||||
def __init__(self, text):
|
def __init__(self, text):
|
||||||
QPushButton.__init__(self, '?')
|
QPushButton.__init__(self, '?')
|
||||||
self.help_text = text
|
self.help_text = text
|
||||||
self.alt_text = None
|
|
||||||
self.setFocusPolicy(Qt.NoFocus)
|
self.setFocusPolicy(Qt.NoFocus)
|
||||||
self.setFixedWidth(20)
|
self.setFixedWidth(20)
|
||||||
self.clicked.connect(lambda: QMessageBox.information(self, 'Help', self.get_text(), 'OK') )
|
self.alt = None
|
||||||
|
self.clicked.connect(self.onclick)
|
||||||
|
|
||||||
def get_text(self):
|
def set_alt(self, func):
|
||||||
return self.alt_text if self.alt_text else self.help_text
|
self.alt = func
|
||||||
|
|
||||||
def set_alt(self, t):
|
|
||||||
self.alt_text = t
|
|
||||||
|
|
||||||
|
def onclick(self):
|
||||||
|
if self.alt:
|
||||||
|
apply(self.alt)
|
||||||
|
else:
|
||||||
|
QMessageBox.information(self, 'Help', self.help_text, 'OK')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,20 +7,19 @@ import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import urllib2
|
import urllib2
|
||||||
|
import urlparse
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import paymentrequest_pb2
|
import paymentrequest_pb2
|
||||||
except:
|
except:
|
||||||
print "protoc --proto_path=lib/ --python_out=lib/ lib/paymentrequest.proto"
|
sys.exit("Error: could not find paymentrequest_pb2.py. Create it with 'protoc --proto_path=lib/ --python_out=lib/ lib/paymentrequest.proto'")
|
||||||
raise Exception()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import requests
|
import requests
|
||||||
except ImportError:
|
except ImportError:
|
||||||
sys.exit("Error: requests does not seem to be installed. Try 'sudo pip install requests'")
|
sys.exit("Error: requests does not seem to be installed. Try 'sudo pip install requests'")
|
||||||
|
|
||||||
import urlparse
|
|
||||||
|
|
||||||
|
|
||||||
import bitcoin
|
import bitcoin
|
||||||
import util
|
import util
|
||||||
|
@ -35,8 +34,7 @@ PR_UNPAID = 0
|
||||||
PR_EXPIRED = 1
|
PR_EXPIRED = 1
|
||||||
PR_SENT = 2 # sent but not propagated
|
PR_SENT = 2 # sent but not propagated
|
||||||
PR_PAID = 3 # send and propagated
|
PR_PAID = 3 # send and propagated
|
||||||
|
PR_ERROR = 4 # could not parse
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ca_list = {}
|
ca_list = {}
|
||||||
|
@ -77,10 +75,12 @@ class PaymentRequest:
|
||||||
self.config = config
|
self.config = config
|
||||||
self.outputs = []
|
self.outputs = []
|
||||||
self.error = ""
|
self.error = ""
|
||||||
|
self.dir_path = os.path.join( self.config.path, 'requests')
|
||||||
|
if not os.path.exists(self.dir_path):
|
||||||
|
os.mkdir(self.dir_path)
|
||||||
|
|
||||||
def read(self, url):
|
def read(self, url):
|
||||||
self.url = url
|
self.url = url
|
||||||
|
|
||||||
u = urlparse.urlparse(url)
|
u = urlparse.urlparse(url)
|
||||||
self.domain = u.netloc
|
self.domain = u.netloc
|
||||||
try:
|
try:
|
||||||
|
@ -97,6 +97,30 @@ class PaymentRequest:
|
||||||
self.error = "cannot read"
|
self.error = "cannot read"
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self.id = bitcoin.sha256(r)[0:16].encode('hex')
|
||||||
|
filename = os.path.join(self.dir_path, self.id)
|
||||||
|
with open(filename,'w') as f:
|
||||||
|
f.write(r)
|
||||||
|
|
||||||
|
return self.parse(r)
|
||||||
|
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
if self.error:
|
||||||
|
return self.error
|
||||||
|
else:
|
||||||
|
return self.status
|
||||||
|
|
||||||
|
|
||||||
|
def read_file(self, key):
|
||||||
|
filename = os.path.join(self.dir_path, key)
|
||||||
|
with open(filename,'r') as f:
|
||||||
|
r = f.read()
|
||||||
|
|
||||||
|
self.parse(r)
|
||||||
|
|
||||||
|
|
||||||
|
def parse(self, r):
|
||||||
try:
|
try:
|
||||||
self.data = paymentrequest_pb2.PaymentRequest()
|
self.data = paymentrequest_pb2.PaymentRequest()
|
||||||
self.data.ParseFromString(r)
|
self.data.ParseFromString(r)
|
||||||
|
@ -104,17 +128,6 @@ class PaymentRequest:
|
||||||
self.error = "cannot parse payment request"
|
self.error = "cannot parse payment request"
|
||||||
return
|
return
|
||||||
|
|
||||||
self.id = bitcoin.sha256(r)[0:16].encode('hex')
|
|
||||||
print self.id
|
|
||||||
|
|
||||||
dir_path = os.path.join( self.config.path, 'requests')
|
|
||||||
if not os.path.exists(dir_path):
|
|
||||||
os.mkdir(dir_path)
|
|
||||||
filename = os.path.join(dir_path, self.id)
|
|
||||||
with open(filename,'w') as f:
|
|
||||||
f.write(r)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def verify(self):
|
def verify(self):
|
||||||
try:
|
try:
|
||||||
|
@ -217,25 +230,28 @@ class PaymentRequest:
|
||||||
|
|
||||||
### SIG Verified
|
### SIG Verified
|
||||||
|
|
||||||
self.payment_details = pay_det = paymentrequest_pb2.PaymentDetails()
|
self.details = pay_det = paymentrequest_pb2.PaymentDetails()
|
||||||
pay_det.ParseFromString(paymntreq.serialized_payment_details)
|
self.details.ParseFromString(paymntreq.serialized_payment_details)
|
||||||
|
|
||||||
if pay_det.expires and pay_det.expires < int(time.time()):
|
|
||||||
self.error = "ERROR: Payment Request has Expired."
|
|
||||||
return False
|
|
||||||
|
|
||||||
for o in pay_det.outputs:
|
for o in pay_det.outputs:
|
||||||
addr = transaction.get_address_from_output_script(o.script)[1]
|
addr = transaction.get_address_from_output_script(o.script)[1]
|
||||||
self.outputs.append( (addr, o.amount) )
|
self.outputs.append( (addr, o.amount) )
|
||||||
|
|
||||||
self.memo = pay_det.memo
|
self.memo = self.details.memo
|
||||||
|
|
||||||
if CA_match:
|
if CA_match:
|
||||||
self.status = 'Signed by Trusted CA:\n' + CA_OU
|
self.status = 'Signed by Trusted CA:\n' + CA_OU
|
||||||
|
|
||||||
print "payment url", pay_det.payment_url
|
self.payment_url = self.details.payment_url
|
||||||
|
|
||||||
|
if self.has_expired():
|
||||||
|
self.error = "ERROR: Payment Request has Expired."
|
||||||
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def has_expired(self):
|
||||||
|
return self.details.expires and self.details.expires < int(time.time())
|
||||||
|
|
||||||
def get_amount(self):
|
def get_amount(self):
|
||||||
return sum(map(lambda x:x[1], self.outputs))
|
return sum(map(lambda x:x[1], self.outputs))
|
||||||
|
@ -246,10 +262,16 @@ class PaymentRequest:
|
||||||
def get_id(self):
|
def get_id(self):
|
||||||
return self.id
|
return self.id
|
||||||
|
|
||||||
|
def get_outputs(self):
|
||||||
|
return self.outputs
|
||||||
|
|
||||||
def send_ack(self, raw_tx, refund_addr):
|
def send_ack(self, raw_tx, refund_addr):
|
||||||
|
|
||||||
pay_det = self.payment_details
|
if self.has_expired():
|
||||||
if not pay_det.payment_url:
|
return False, "has expired"
|
||||||
|
|
||||||
|
pay_det = self.details
|
||||||
|
if not self.details.payment_url:
|
||||||
return False, "no url"
|
return False, "no url"
|
||||||
|
|
||||||
paymnt = paymentrequest_pb2.Payment()
|
paymnt = paymentrequest_pb2.Payment()
|
||||||
|
@ -302,7 +324,7 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
print 'Payment Request Verified Domain: ', pr.domain
|
print 'Payment Request Verified Domain: ', pr.domain
|
||||||
print 'outputs', pr.outputs
|
print 'outputs', pr.outputs
|
||||||
print 'Payment Memo: ', pr.payment_details.memo
|
print 'Payment Memo: ', pr.details.memo
|
||||||
|
|
||||||
tx = "blah"
|
tx = "blah"
|
||||||
pr.send_ack(tx, refund_addr = "1vXAXUnGitimzinpXrqDWVU4tyAAQ34RA")
|
pr.send_ack(tx, refund_addr = "1vXAXUnGitimzinpXrqDWVU4tyAAQ34RA")
|
||||||
|
|
Loading…
Reference in New Issue