Zcash changes to lib

This commit is contained in:
zebra-lucky 2018-03-11 03:23:24 +02:00
parent 717b3d7df2
commit 9f61882b3a
22 changed files with 130 additions and 388 deletions

View File

@ -43,7 +43,7 @@ if jnius:
script_dir = os.path.dirname(os.path.realpath(__file__)) script_dir = os.path.dirname(os.path.realpath(__file__))
is_bundle = getattr(sys, 'frozen', False) is_bundle = getattr(sys, 'frozen', False)
is_local = not is_bundle and os.path.exists(os.path.join(script_dir, "electrum.desktop")) is_local = not is_bundle and os.path.exists(os.path.join(script_dir, "electrum-zcash.desktop"))
is_android = 'ANDROID_DATA' in os.environ is_android = 'ANDROID_DATA' in os.environ
# move this back to gui/kivy/__init.py once plugins are moved # move this back to gui/kivy/__init.py once plugins are moved
@ -82,22 +82,22 @@ if not is_android:
# load local module as electrum # load local module as electrum
if is_local or is_android: if is_local or is_android:
import imp import imp
imp.load_module('electrum', *imp.find_module('lib')) imp.load_module('electrum_zcash', *imp.find_module('lib'))
imp.load_module('electrum_gui', *imp.find_module('gui')) imp.load_module('electrum_zcash_gui', *imp.find_module('gui'))
imp.load_module('electrum_plugins', *imp.find_module('plugins')) imp.load_module('electrum_zcash_plugins', *imp.find_module('plugins'))
from electrum import bitcoin from electrum_zcash import bitcoin
from electrum import SimpleConfig, Network from electrum_zcash import SimpleConfig, Network
from electrum.wallet import Wallet, Imported_Wallet from electrum_zcash.wallet import Wallet, Imported_Wallet
from electrum.storage import WalletStorage from electrum_zcash.storage import WalletStorage
from electrum.util import print_msg, print_stderr, json_encode, json_decode from electrum_zcash.util import print_msg, print_stderr, json_encode, json_decode
from electrum.util import set_verbosity, InvalidPassword, check_www_dir from electrum_zcash.util import set_verbosity, InvalidPassword, check_www_dir
from electrum.commands import get_parser, known_commands, Commands, config_variables from electrum_zcash.commands import get_parser, known_commands, Commands, config_variables
from electrum import daemon from electrum_zcash import daemon
from electrum import keystore from electrum_zcash import keystore
from electrum.mnemonic import Mnemonic from electrum_zcash.mnemonic import Mnemonic
import electrum_plugins import electrum_zcash_plugins
# get password routine # get password routine
def prompt_password(prompt, confirm=True): def prompt_password(prompt, confirm=True):
@ -189,7 +189,7 @@ def init_daemon(config_options):
storage = WalletStorage(config.get_wallet_path()) storage = WalletStorage(config.get_wallet_path())
if not storage.file_exists(): if not storage.file_exists():
print_msg("Error: Wallet file not found.") print_msg("Error: Wallet file not found.")
print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option") print_msg("Type 'electrum-zcash create' to create a new wallet, or provide a path to a wallet with the -w option")
sys.exit(0) sys.exit(0)
if storage.is_encrypted(): if storage.is_encrypted():
if config.get('password'): if config.get('password'):
@ -224,7 +224,7 @@ def init_cmdline(config_options, server):
if cmd.requires_wallet and not storage.file_exists(): if cmd.requires_wallet and not storage.file_exists():
print_msg("Error: Wallet file not found.") print_msg("Error: Wallet file not found.")
print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option") print_msg("Type 'electrum-zcash create' to create a new wallet, or provide a path to a wallet with the -w option")
sys.exit(0) sys.exit(0)
# important warning # important warning
@ -292,7 +292,7 @@ def run_offline_command(config, config_options):
return result return result
def init_plugins(config, gui_name): def init_plugins(config, gui_name):
from electrum.plugins import Plugins from electrum_zcash.plugins import Plugins
return Plugins(config, is_local or is_android, gui_name) return Plugins(config, is_local or is_android, gui_name)
if __name__ == '__main__': if __name__ == '__main__':
@ -351,7 +351,7 @@ if __name__ == '__main__':
# check uri # check uri
uri = config_options.get('url') uri = config_options.get('url')
if uri: if uri:
if not uri.startswith('bitcoin:'): if not uri.startswith('zcash:'):
print_stderr('unknown command:', uri) print_stderr('unknown command:', uri)
sys.exit(1) sys.exit(1)
config_options['url'] = uri config_options['url'] = uri
@ -396,7 +396,7 @@ if __name__ == '__main__':
d = daemon.Daemon(config, fd, False) d = daemon.Daemon(config, fd, False)
d.start() d.start()
if config.get('websocket_server'): if config.get('websocket_server'):
from electrum import websockets from electrum_zcash import websockets
websockets.WebSocketServer(config, d.network).start() websockets.WebSocketServer(config, d.network).start()
if config.get('requests_dir'): if config.get('requests_dir'):
check_www_dir(config.get('requests_dir')) check_www_dir(config.get('requests_dir'))
@ -420,7 +420,7 @@ if __name__ == '__main__':
else: else:
cmd = known_commands[cmdname] cmd = known_commands[cmdname]
if cmd.requires_network: if cmd.requires_network:
print_msg("Daemon not running; try 'electrum daemon start'") print_msg("Daemon not running; try 'electrum-zcash daemon start'")
sys.exit(1) sys.exit(1)
else: else:
init_plugins(config, 'cmdline') init_plugins(config, 'cmdline')

View File

@ -19,6 +19,6 @@ fi
export PYTHONPATH="/usr/local/lib/python3.5/site-packages:$PYTHONPATH" export PYTHONPATH="/usr/local/lib/python3.5/site-packages:$PYTHONPATH"
./electrum "$@" ./electrum-zcash "$@"
deactivate deactivate

View File

@ -1,7 +1,7 @@
# Configuration file for the electrum client # Configuration file for the electrum-zcash client
# Settings defined here are shared across wallets # Settings defined here are shared across wallets
# #
# copy this file to /etc/electrum.conf if you want read-only settings # copy this file to /etc/electrum-zcash.conf if you want read-only settings
[client] [client]
server = electrum.novit.ro:50001:t server = electrum.novit.ro:50001:t

17
electrum-zcash.desktop Normal file
View File

@ -0,0 +1,17 @@
# If you want electrum-zcash to appear in a linux app launcher ("start menu"), install this by doing:
# sudo desktop-file-install electrum-zcash.desktop
[Desktop Entry]
Comment=Lightweight Zcash Client
Exec=electrum-zcash %u
GenericName[en_US]=Zcash Wallet
GenericName=Zcash Wallet
Icon=electrum-zcash.png
Name[en_US]=Electrum-Zcash Bitcoin Wallet
Name=Electrum-Zcash Bitcoin Wallet
Categories=Finance;Network;
StartupNotify=false
Terminal=false
Type=Application
MimeType=x-scheme-handler/zcash;

View File

@ -1,17 +0,0 @@
# If you want electrum to appear in a linux app launcher ("start menu"), install this by doing:
# sudo desktop-file-install electrum.desktop
[Desktop Entry]
Comment=Lightweight Bitcoin Client
Exec=electrum %u
GenericName[en_US]=Bitcoin Wallet
GenericName=Bitcoin Wallet
Icon=electrum
Name[en_US]=Electrum Bitcoin Wallet
Name=Electrum Bitcoin Wallet
Categories=Finance;Network;
StartupNotify=false
Terminal=false
Type=Application
MimeType=x-scheme-handler/bitcoin;

View File

@ -79,27 +79,18 @@ class BaseWizard(object):
]) ])
wallet_kinds = [ wallet_kinds = [
('standard', _("Standard wallet")), ('standard', _("Standard wallet")),
('2fa', _("Wallet with two-factor authentication")),
('multisig', _("Multi-signature wallet")), ('multisig', _("Multi-signature wallet")),
('imported', _("Import Bitcoin addresses or private keys")), ('imported', _("Import Zcash addresses or private keys")),
] ]
choices = [pair for pair in wallet_kinds if pair[0] in wallet_types] choices = [pair for pair in wallet_kinds if pair[0] in wallet_types]
self.choice_dialog(title=title, message=message, choices=choices, run_next=self.on_wallet_type) self.choice_dialog(title=title, message=message, choices=choices, run_next=self.on_wallet_type)
def load_2fa(self):
self.storage.put('wallet_type', '2fa')
self.storage.put('use_trustedcoin', True)
self.plugin = self.plugins.load_plugin('trustedcoin')
def on_wallet_type(self, choice): def on_wallet_type(self, choice):
self.wallet_type = choice self.wallet_type = choice
if choice == 'standard': if choice == 'standard':
action = 'choose_keystore' action = 'choose_keystore'
elif choice == 'multisig': elif choice == 'multisig':
action = 'choose_multisig' action = 'choose_multisig'
elif choice == '2fa':
self.load_2fa()
action = self.storage.get_action()
elif choice == 'imported': elif choice == 'imported':
action = 'import_addresses_or_keys' action = 'import_addresses_or_keys'
self.run(action) self.run(action)
@ -138,8 +129,8 @@ class BaseWizard(object):
def import_addresses_or_keys(self): def import_addresses_or_keys(self):
v = lambda x: keystore.is_address_list(x) or keystore.is_private_key_list(x) v = lambda x: keystore.is_address_list(x) or keystore.is_private_key_list(x)
title = _("Import Bitcoin Addresses") title = _("Import Zcash Addresses")
message = _("Enter a list of Bitcoin addresses (this will create a watching-only wallet), or a list of private keys.") message = _("Enter a list of Zcash addresses (this will create a watching-only wallet), or a list of private keys.")
self.add_xpub_dialog(title=title, message=message, run_next=self.on_import, is_valid=v) self.add_xpub_dialog(title=title, message=message, run_next=self.on_import, is_valid=v)
def on_import(self, text): def on_import(self, text):
@ -160,8 +151,8 @@ class BaseWizard(object):
v = keystore.is_master_key v = keystore.is_master_key
title = _("Create keystore from a master key") title = _("Create keystore from a master key")
message = ' '.join([ message = ' '.join([
_("To create a watching-only wallet, please enter your master public key (xpub/ypub/zpub)."), _("To create a watching-only wallet, please enter your master public key (xpub)."),
_("To create a spending wallet, please enter a master private key (xprv/yprv/zprv).") _("To create a spending wallet, please enter a master private key (xprv).")
]) ])
self.add_xpub_dialog(title=title, message=message, run_next=self.on_restore_from_key, is_valid=v) self.add_xpub_dialog(title=title, message=message, run_next=self.on_restore_from_key, is_valid=v)
else: else:
@ -285,13 +276,6 @@ class BaseWizard(object):
self.passphrase_dialog(run_next=f) if is_ext else f('') self.passphrase_dialog(run_next=f) if is_ext else f('')
elif self.seed_type == 'old': elif self.seed_type == 'old':
self.run('create_keystore', seed, '') self.run('create_keystore', seed, '')
elif self.seed_type == '2fa':
if self.is_kivy:
self.show_error('2FA seeds are not supported in this version')
self.run('restore_from_seed')
else:
self.load_2fa()
self.run('on_restore_seed', seed, is_ext)
else: else:
raise BaseException('Unknown seed type', self.seed_type) raise BaseException('Unknown seed type', self.seed_type)
@ -424,5 +408,5 @@ class BaseWizard(object):
self.wallet.synchronize() self.wallet.synchronize()
self.wallet.storage.write() self.wallet.storage.write()
self.terminate() self.terminate()
msg = _("Electrum is generating your addresses, please wait.") msg = _("Electrum-Zcash is generating your addresses, please wait.")
self.waiting_dialog(task, msg) self.waiting_dialog(task, msg)

View File

@ -271,8 +271,6 @@ def seed_type(x):
return 'old' return 'old'
elif is_new_seed(x): elif is_new_seed(x):
return 'standard' return 'standard'
elif is_new_seed(x, version.SEED_PREFIX_2FA):
return '2fa'
return '' return ''
is_seed = lambda x: bool(seed_type(x)) is_seed = lambda x: bool(seed_type(x))
@ -558,7 +556,7 @@ from ecdsa.util import string_to_number, number_to_string
def msg_magic(message): def msg_magic(message):
length = bfh(var_int(len(message))) length = bfh(var_int(len(message)))
return b"\x18Bitcoin Signed Message:\n" + length + message return b"\x18Zcash Signed Message:\n" + length + message
def verify_message(address, sig, message): def verify_message(address, sig, message):

View File

@ -81,7 +81,7 @@ def command(s):
wallet = args[0].wallet wallet = args[0].wallet
password = kwargs.get('password') password = kwargs.get('password')
if c.requires_wallet and wallet is None: if c.requires_wallet and wallet is None:
raise BaseException("wallet not loaded. Use 'electrum daemon load_wallet'") raise BaseException("wallet not loaded. Use 'electrum-zcash daemon load_wallet'")
if c.requires_password and password is None and wallet.storage.get('use_encryption'): if c.requires_password and password is None and wallet.storage.get('use_encryption'):
return {'error': 'Password required' } return {'error': 'Password required' }
return func(*args, **kwargs) return func(*args, **kwargs)
@ -130,8 +130,8 @@ class Commands:
@command('wn') @command('wn')
def restore(self, text): def restore(self, text):
"""Restore a wallet from text. Text can be a seed phrase, a master """Restore a wallet from text. Text can be a seed phrase, a master
public key, a master private key, a list of bitcoin addresses public key, a master private key, a list of Zcash addresses
or bitcoin private keys. If you want to be prompted for your or Zcash private keys. If you want to be prompted for your
seed, type '?' or ':' (concealed) """ seed, type '?' or ':' (concealed) """
raise BaseException('Not a JSON-RPC command') raise BaseException('Not a JSON-RPC command')
@ -288,7 +288,7 @@ class Commands:
@command('') @command('')
def dumpprivkeys(self): def dumpprivkeys(self):
"""Deprecated.""" """Deprecated."""
return "This command is deprecated. Use a pipe instead: 'electrum listaddresses | electrum getprivatekeys - '" return "This command is deprecated. Use a pipe instead: 'electrum-zcash listaddresses | electrum-zcash getprivatekeys - '"
@command('') @command('')
def validateaddress(self, address): def validateaddress(self, address):
@ -332,7 +332,7 @@ class Commands:
@command('n') @command('n')
def getmerkle(self, txid, height): def getmerkle(self, txid, height):
"""Get Merkle branch of a transaction included in a block. Electrum """Get Merkle branch of a transaction included in a block. Electrum-Zcash
uses this to verify transactions (Simple Payment Verification).""" uses this to verify transactions (Simple Payment Verification)."""
return self.network.synchronous_get(('blockchain.transaction.get_merkle', [txid, int(height)])) return self.network.synchronous_get(('blockchain.transaction.get_merkle', [txid, int(height)]))
@ -343,7 +343,7 @@ class Commands:
@command('') @command('')
def version(self): def version(self):
"""Return the version of electrum.""" """Return the version of electrum-zcash."""
from .version import ELECTRUM_VERSION from .version import ELECTRUM_VERSION
return ELECTRUM_VERSION return ELECTRUM_VERSION
@ -491,7 +491,7 @@ class Commands:
@command('w') @command('w')
def setlabel(self, key, label): def setlabel(self, key, label):
"""Assign a label to an item. Item may be a bitcoin address or a """Assign a label to an item. Item may be a Zcash address or a
transaction ID""" transaction ID"""
self.wallet.set_label(key, label) self.wallet.set_label(key, label)
@ -569,7 +569,7 @@ class Commands:
PR_PAID: 'Paid', PR_PAID: 'Paid',
PR_EXPIRED: 'Expired', PR_EXPIRED: 'Expired',
} }
out['amount (BTC)'] = format_satoshis(out.get('amount')) out['amount (ZEC)'] = format_satoshis(out.get('amount'))
out['status'] = pr_str[out.get('status', PR_UNKNOWN)] out['status'] = pr_str[out.get('status', PR_UNKNOWN)]
return out return out
@ -679,8 +679,8 @@ class Commands:
param_descriptions = { param_descriptions = {
'privkey': 'Private key. Type \'?\' to get a prompt.', 'privkey': 'Private key. Type \'?\' to get a prompt.',
'destination': 'Bitcoin address, contact or alias', 'destination': 'Zcash address, contact or alias',
'address': 'Bitcoin address', 'address': 'Zcash address',
'seed': 'Seed phrase', 'seed': 'Seed phrase',
'txid': 'Transaction ID', 'txid': 'Transaction ID',
'pos': 'Position', 'pos': 'Position',
@ -690,8 +690,8 @@ param_descriptions = {
'pubkey': 'Public key', 'pubkey': 'Public key',
'message': 'Clear text message. Use quotes if it contains spaces.', 'message': 'Clear text message. Use quotes if it contains spaces.',
'encrypted': 'Encrypted message', 'encrypted': 'Encrypted message',
'amount': 'Amount to be sent (in BTC). Type \'!\' to send the maximum available.', 'amount': 'Amount to be sent (in ZEC). Type \'!\' to send the maximum available.',
'requested_amount': 'Requested amount (in BTC).', 'requested_amount': 'Requested amount (in ZEC).',
'outputs': 'list of ["address", amount]', 'outputs': 'list of ["address", amount]',
'redeem_script': 'redeem script (hexadecimal)', 'redeem_script': 'redeem script (hexadecimal)',
} }
@ -708,7 +708,7 @@ command_options = {
'labels': ("-l", "Show the labels of listed addresses"), 'labels': ("-l", "Show the labels of listed addresses"),
'nocheck': (None, "Do not verify aliases"), 'nocheck': (None, "Do not verify aliases"),
'imax': (None, "Maximum number of inputs"), 'imax': (None, "Maximum number of inputs"),
'fee': ("-f", "Transaction fee (in BTC)"), 'fee': ("-f", "Transaction fee (in ZEC)"),
'from_addr': ("-F", "Source address (must be a wallet address; use sweep to spend from non-wallet address)."), 'from_addr': ("-F", "Source address (must be a wallet address; use sweep to spend from non-wallet address)."),
'change_addr': ("-c", "Change address. Default is a spare address, or the source address if it's not in the wallet"), 'change_addr': ("-c", "Change address. Default is a spare address, or the source address if it's not in the wallet"),
'nbits': (None, "Number of bits of entropy"), 'nbits': (None, "Number of bits of entropy"),
@ -753,10 +753,10 @@ config_variables = {
'requests_dir': 'directory where a bip70 file will be written.', 'requests_dir': 'directory where a bip70 file will be written.',
'ssl_privkey': 'Path to your SSL private key, needed to sign the request.', 'ssl_privkey': 'Path to your SSL private key, needed to sign the request.',
'ssl_chain': 'Chain of SSL certificates, needed for signed requests. Put your certificate at the top and the root CA at the end', 'ssl_chain': 'Chain of SSL certificates, needed for signed requests. Put your certificate at the top and the root CA at the end',
'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of bitcoin: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"', 'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of zcash: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"',
}, },
'listrequests':{ 'listrequests':{
'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of bitcoin: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"', 'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of zcash: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"',
} }
} }
@ -820,7 +820,7 @@ def add_network_options(parser):
def add_global_options(parser): def add_global_options(parser):
group = parser.add_argument_group('global options') group = parser.add_argument_group('global options')
group.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Show debugging information") group.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Show debugging information")
group.add_argument("-D", "--dir", dest="electrum_path", help="electrum directory") group.add_argument("-D", "--dir", dest="electrum_path", help="electrum-zcash directory")
group.add_argument("-P", "--portable", action="store_true", dest="portable", default=False, help="Use local 'electrum_data' directory") group.add_argument("-P", "--portable", action="store_true", dest="portable", default=False, help="Use local 'electrum_data' directory")
group.add_argument("-w", "--wallet", dest="wallet_path", help="wallet path") group.add_argument("-w", "--wallet", dest="wallet_path", help="wallet path")
group.add_argument("--testnet", action="store_true", dest="testnet", default=False, help="Use Testnet") group.add_argument("--testnet", action="store_true", dest="testnet", default=False, help="Use Testnet")
@ -828,12 +828,12 @@ def add_global_options(parser):
def get_parser(): def get_parser():
# create main parser # create main parser
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
epilog="Run 'electrum help <command>' to see the help for a command") epilog="Run 'electrum-zcash help <command>' to see the help for a command")
add_global_options(parser) add_global_options(parser)
subparsers = parser.add_subparsers(dest='cmd', metavar='<command>') subparsers = parser.add_subparsers(dest='cmd', metavar='<command>')
# gui # gui
parser_gui = subparsers.add_parser('gui', description="Run Electrum's Graphical User Interface.", help="Run GUI (default)") parser_gui = subparsers.add_parser('gui', description="Run Electrum-Zcash Graphical User Interface.", help="Run GUI (default)")
parser_gui.add_argument("url", nargs='?', default=None, help="bitcoin URI (or bip70 file)") parser_gui.add_argument("url", nargs='?', default=None, help="Zcash URI (or bip70 file)")
parser_gui.add_argument("-g", "--gui", dest="gui", help="select graphical user interface", choices=['qt', 'kivy', 'text', 'stdio']) parser_gui.add_argument("-g", "--gui", dest="gui", help="select graphical user interface", choices=['qt', 'kivy', 'text', 'stdio'])
parser_gui.add_argument("-o", "--offline", action="store_true", dest="offline", default=False, help="Run offline") parser_gui.add_argument("-o", "--offline", action="store_true", dest="offline", default=False, help="Run offline")
parser_gui.add_argument("-m", action="store_true", dest="hide_gui", default=False, help="hide GUI on startup") parser_gui.add_argument("-m", action="store_true", dest="hide_gui", default=False, help="hide GUI on startup")

View File

@ -87,13 +87,13 @@ class Contacts(dict):
'type': 'openalias', 'type': 'openalias',
'validated': validated 'validated': validated
} }
raise Exception("Invalid Bitcoin address or alias", k) raise Exception("Invalid Zcash address or alias", k)
def resolve_openalias(self, url): def resolve_openalias(self, url):
# support email-style addresses, per the OA standard # support email-style addresses, per the OA standard
url = url.replace('@', '.') url = url.replace('@', '.')
records, validated = dnssec.query(url, dns.rdatatype.TXT) records, validated = dnssec.query(url, dns.rdatatype.TXT)
prefix = 'btc' prefix = 'zcash'
for record in records: for record in records:
string = record.strings[0] string = record.strings[0]
if string.startswith('oa1:' + prefix): if string.startswith('oa1:' + prefix):

View File

@ -299,6 +299,6 @@ class Daemon(DaemonThread):
gui_name = config.get('gui', 'qt') gui_name = config.get('gui', 'qt')
if gui_name in ['lite', 'classic']: if gui_name in ['lite', 'classic']:
gui_name = 'qt' gui_name = 'qt'
gui = __import__('electrum_gui.' + gui_name, fromlist=['electrum_gui']) gui = __import__('electrum_zcash_gui.' + gui_name, fromlist=['electrum_zcash_gui'])
self.gui = gui.ElectrumGui(config, self, plugins) self.gui = gui.ElectrumGui(config, self, plugins)
self.gui.main() self.gui.main()

View File

@ -46,8 +46,8 @@ from . import rsakey
from .bitcoin import TYPE_ADDRESS from .bitcoin import TYPE_ADDRESS
REQUEST_HEADERS = {'Accept': 'application/bitcoin-paymentrequest', 'User-Agent': 'Electrum'} REQUEST_HEADERS = {'Accept': 'application/zcash-paymentrequest', 'User-Agent': 'Electrum-Zcash'}
ACK_HEADERS = {'Content-Type':'application/bitcoin-payment','Accept':'application/bitcoin-paymentack','User-Agent':'Electrum'} ACK_HEADERS = {'Content-Type':'application/zcash-payment','Accept':'application/zcash-paymentack','User-Agent':'Electrum-Zcash'}
ca_path = requests.certs.where() ca_path = requests.certs.where()
ca_list = None ca_list = None
@ -75,9 +75,9 @@ def get_payment_request(url):
try: try:
response = requests.request('GET', url, headers=REQUEST_HEADERS) response = requests.request('GET', url, headers=REQUEST_HEADERS)
response.raise_for_status() response.raise_for_status()
# Guard against `bitcoin:`-URIs with invalid payment request URLs # Guard against `zcash:`-URIs with invalid payment request URLs
if "Content-Type" not in response.headers \ if "Content-Type" not in response.headers \
or response.headers["Content-Type"] != "application/bitcoin-paymentrequest": or response.headers["Content-Type"] != "application/zcash-paymentrequest":
data = None data = None
error = "payment URL not pointing to a payment request handling server" error = "payment URL not pointing to a payment request handling server"
else: else:
@ -266,7 +266,7 @@ class PaymentRequest:
paymnt.transactions.append(bfh(raw_tx)) paymnt.transactions.append(bfh(raw_tx))
ref_out = paymnt.refund_to.add() ref_out = paymnt.refund_to.add()
ref_out.script = util.bfh(transaction.Transaction.pay_script(TYPE_ADDRESS, refund_addr)) ref_out.script = util.bfh(transaction.Transaction.pay_script(TYPE_ADDRESS, refund_addr))
paymnt.memo = "Paid using Electrum" paymnt.memo = "Paid using Electrum-Zcash"
pm = paymnt.SerializeToString() pm = paymnt.SerializeToString()
payurl = urllib.parse.urlparse(pay_det.payment_url) payurl = urllib.parse.urlparse(pay_det.payment_url)
try: try:

View File

@ -35,7 +35,7 @@ def plot_history(wallet, history):
plt.subplots_adjust(bottom=0.2) plt.subplots_adjust(bottom=0.2)
plt.xticks( rotation=25 ) plt.xticks( rotation=25 )
ax = plt.gca() ax = plt.gca()
plt.ylabel('BTC') plt.ylabel('ZEC')
plt.xlabel('Month') plt.xlabel('Month')
xfmt = md.DateFormatter('%Y-%m-%d') xfmt = md.DateFormatter('%Y-%m-%d')
ax.xaxis.set_major_formatter(xfmt) ax.xaxis.set_major_formatter(xfmt)

View File

@ -48,9 +48,9 @@ class Plugins(DaemonThread):
DaemonThread.__init__(self) DaemonThread.__init__(self)
if is_local: if is_local:
find = imp.find_module('plugins') find = imp.find_module('plugins')
plugins = imp.load_module('electrum_plugins', *find) plugins = imp.load_module('electrum_zcash_plugins', *find)
else: else:
plugins = __import__('electrum_plugins') plugins = __import__('electrum_zcash_plugins')
self.pkgpath = os.path.dirname(plugins.__file__) self.pkgpath = os.path.dirname(plugins.__file__)
self.config = config self.config = config
self.hw_wallets = {} self.hw_wallets = {}
@ -95,7 +95,7 @@ class Plugins(DaemonThread):
def load_plugin(self, name): def load_plugin(self, name):
if name in self.plugins: if name in self.plugins:
return self.plugins[name] return self.plugins[name]
full_name = 'electrum_plugins.' + name + '.' + self.gui_name full_name = 'electrum_zcash_plugins.' + name + '.' + self.gui_name
loader = pkgutil.find_loader(full_name) loader = pkgutil.find_loader(full_name)
if not loader: if not loader:
raise RuntimeError("%s implementation for %s plugin not found" raise RuntimeError("%s implementation for %s plugin not found"
@ -442,10 +442,10 @@ class DeviceMgr(ThreadJob, PrintError):
# The user input has wrong PIN or passphrase, or cancelled input, # The user input has wrong PIN or passphrase, or cancelled input,
# or it is not pairable # or it is not pairable
raise DeviceUnpairableError( raise DeviceUnpairableError(
_('Electrum cannot pair with your %s.\n\n' _('Electrum-Zcash cannot pair with your %s.\n\n'
'Before you request bitcoins to be sent to addresses in this ' 'Before you request Zcash coins to be sent to addresses in this '
'wallet, ensure you can pair with your device, or that you have ' 'wallet, ensure you can pair with your device, or that you have '
'its seed (and passphrase, if any). Otherwise all bitcoins you ' 'its seed (and passphrase, if any). Otherwise all coins you '
'receive will be unspendable.') % plugin.device) 'receive will be unspendable.') % plugin.device)
def unpaired_device_infos(self, handler, plugin, devices=None): def unpaired_device_infos(self, handler, plugin, devices=None):

View File

@ -1,228 +1,5 @@
{ {
"E-X.not.fyi": { "localhost": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"ELECTRUMX.not.fyi": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"ELEX01.blackpole.online": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"VPS.hsmiths.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"bitcoin.freedomnode.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"btc.smsys.me": {
"pruning": "-",
"s": "995",
"version": "1.1"
},
"currentlane.lovebitco.in": {
"pruning": "-",
"t": "50001",
"version": "1.1"
},
"daedalus.bauerj.eu": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"de01.hamster.science": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"ecdsa.net": {
"pruning": "-",
"s": "110",
"t": "50001",
"version": "1.1"
},
"elec.luggs.co": {
"pruning": "-",
"s": "443",
"version": "1.1"
},
"electrum.akinbo.org": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.antumbra.se": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.be": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.coinucopia.io": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.cutie.ga": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.festivaldelhumor.org": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.hsmiths.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.qtornado.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.vom-stausee.de": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum3.hachre.de": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrumx.bot.nu": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrumx.westeurope.cloudapp.azure.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"elx01.knas.systems": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"ex-btc.server-on.net": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"helicarrier.bauerj.eu": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"mooo.not.fyi": {
"pruning": "-",
"s": "50012",
"t": "50011",
"version": "1.1"
},
"ndnd.selfhost.eu": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"node.arihanc.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"node.xbt.eu": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"node1.volatilevictory.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"noserver4u.de": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"qmebr.spdns.org": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"raspi.hsmiths.com": {
"pruning": "-",
"s": "51002",
"t": "51001",
"version": "1.1"
},
"s2.noip.pl": {
"pruning": "-",
"s": "50102",
"version": "1.1"
},
"s5.noip.pl": {
"pruning": "-",
"s": "50105",
"version": "1.1"
},
"songbird.bauerj.eu": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"us.electrum.be": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"us01.hamster.science": {
"pruning": "-", "pruning": "-",
"s": "50002", "s": "50002",
"t": "50001", "t": "50001",

View File

@ -1,8 +1,8 @@
{ {
"testnetnode.arihanc.com": {"t":"51001", "s":"51002"}, "localhost": {
"testnet1.bauerj.eu": {"t":"51001", "s":"51002"}, "pruning": "-",
"14.3.140.101": {"t":"51001", "s":"51002"}, "s": "50002",
"testnet.hsmiths.com": {"t":"53011", "s":"53012"}, "t": "50001",
"electrum.akinbo.org": {"t":"51001", "s":"51002"}, "version": "1.1"
"ELEX05.blackpole.online": {"t":"52011", "s":"52002"} }
} }

View File

@ -9,7 +9,7 @@ from .util import user_dir, print_error, print_stderr, PrintError
from .bitcoin import MAX_FEE_RATE, FEE_TARGETS from .bitcoin import MAX_FEE_RATE, FEE_TARGETS
SYSTEM_CONFIG_PATH = "/etc/electrum.conf" SYSTEM_CONFIG_PATH = "/etc/electrum-zcash.conf"
config = None config = None
@ -92,10 +92,10 @@ class SimpleConfig(PrintError):
if not os.path.exists(path): if not os.path.exists(path):
if os.path.islink(path): if os.path.islink(path):
raise BaseException('Dangling link: ' + path) raise BaseException('Dangling link: ' + path)
os.mkdir(path) os.makedirs(path)
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
self.print_error("electrum directory", path) self.print_error("electrum-zcash directory", path)
return path return path
def fixup_config_keys(self, config, keypairs): def fixup_config_keys(self, config, keypairs):
@ -278,7 +278,7 @@ class SimpleConfig(PrintError):
def read_system_config(path=SYSTEM_CONFIG_PATH): def read_system_config(path=SYSTEM_CONFIG_PATH):
"""Parse and return the system config settings in /etc/electrum.conf.""" """Parse and return the system config settings in /etc/electrum-zcash.conf."""
result = {} result = {}
if os.path.exists(path): if os.path.exists(path):
import configparser import configparser
@ -293,7 +293,7 @@ def read_system_config(path=SYSTEM_CONFIG_PATH):
return result return result
def read_user_config(path): def read_user_config(path):
"""Parse and store the user config settings in electrum.conf into user_config[].""" """Parse and store the user config settings in electrum-zcash.conf into user_config[]."""
if not path: if not path:
return {} return {}
config_path = os.path.join(path, "config") config_path = os.path.join(path, "config")

View File

@ -327,7 +327,7 @@ class WalletStorage(PrintError):
self.put('wallet_type', 'standard') self.put('wallet_type', 'standard')
self.put('keystore', d) self.put('keystore', d)
elif (wallet_type == '2fa') or multisig_type(wallet_type): elif multisig_type(wallet_type):
for key in xpubs.keys(): for key in xpubs.keys():
d = { d = {
'type': 'bip32', 'type': 'bip32',

View File

@ -809,7 +809,7 @@ class Transaction:
secexp = pkey.secret secexp = pkey.secret
private_key = bitcoin.MySigningKey.from_secret_exponent(secexp, curve = SECP256k1) private_key = bitcoin.MySigningKey.from_secret_exponent(secexp, curve = SECP256k1)
public_key = private_key.get_verifying_key() public_key = private_key.get_verifying_key()
sig = private_key.sign_digest_deterministic(pre_hash, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der) sig = private_key.sign_digest_deterministic(pre_hash, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der_canonize)
assert public_key.verify_digest(sig, pre_hash, sigdecode = ecdsa.util.sigdecode_der) assert public_key.verify_digest(sig, pre_hash, sigdecode = ecdsa.util.sigdecode_der)
txin['signatures'][j] = bh2u(sig) + '01' txin['signatures'][j] = bh2u(sig) + '01'
#txin['x_pubkeys'][j] = pubkey #txin['x_pubkeys'][j] = pubkey

View File

@ -40,7 +40,7 @@ def inv_dict(d):
return {v: k for k, v in d.items()} return {v: k for k, v in d.items()}
base_units = {'BTC':8, 'mBTC':5, 'uBTC':2} base_units = {'ZEC':8, 'mZEC':5, 'uZEC':2}
fee_levels = [_('Within 25 blocks'), _('Within 10 blocks'), _('Within 5 blocks'), _('Within 2 blocks'), _('In the next block')] fee_levels = [_('Within 25 blocks'), _('Within 10 blocks'), _('Within 5 blocks'), _('Within 2 blocks'), _('In the next block')]
def normalize_version(v): def normalize_version(v):
@ -216,6 +216,14 @@ def profiler(func):
return lambda *args, **kw_args: do_profile(func, args, kw_args) return lambda *args, **kw_args: do_profile(func, args, kw_args)
def android_headers_file_name():
from bitcoin import TESTNET
s = 'blockchain_headers'
if TESTNET:
s += '_testnet'
return s
def android_ext_dir(): def android_ext_dir():
import jnius import jnius
env = jnius.autoclass('android.os.Environment') env = jnius.autoclass('android.os.Environment')
@ -227,7 +235,7 @@ def android_data_dir():
return PythonActivity.mActivity.getFilesDir().getPath() + '/data' return PythonActivity.mActivity.getFilesDir().getPath() + '/data'
def android_headers_dir(): def android_headers_dir():
d = android_ext_dir() + '/org.electrum.electrum' d = android_ext_dir() + '/org.electrum-zcash.electrum-zcash'
if not os.path.exists(d): if not os.path.exists(d):
os.mkdir(d) os.mkdir(d)
return d return d
@ -236,11 +244,11 @@ def android_check_data_dir():
""" if needed, move old directory to sandbox """ """ if needed, move old directory to sandbox """
ext_dir = android_ext_dir() ext_dir = android_ext_dir()
data_dir = android_data_dir() data_dir = android_data_dir()
old_electrum_dir = ext_dir + '/electrum' old_electrum_dir = ext_dir + '/electrum-zcash'
if not os.path.exists(data_dir) and os.path.exists(old_electrum_dir): if not os.path.exists(data_dir) and os.path.exists(old_electrum_dir):
import shutil import shutil
new_headers_path = android_headers_dir() + '/blockchain_headers' new_headers_path = android_headers_dir() + android_headers_file_name()
old_headers_path = old_electrum_dir + '/blockchain_headers' old_headers_path = old_electrum_dir + android_headers_file_name()
if not os.path.exists(new_headers_path) and os.path.exists(old_headers_path): if not os.path.exists(new_headers_path) and os.path.exists(old_headers_path):
print_error("Moving headers file to", new_headers_path) print_error("Moving headers file to", new_headers_path)
shutil.move(old_headers_path, new_headers_path) shutil.move(old_headers_path, new_headers_path)
@ -317,11 +325,11 @@ def user_dir():
if 'ANDROID_DATA' in os.environ: if 'ANDROID_DATA' in os.environ:
return android_check_data_dir() return android_check_data_dir()
elif os.name == 'posix': elif os.name == 'posix':
return os.path.join(os.environ["HOME"], ".electrum") return os.path.join(os.environ["HOME"], ".electrum-zcash")
elif "APPDATA" in os.environ: elif "APPDATA" in os.environ:
return os.path.join(os.environ["APPDATA"], "Electrum") return os.path.join(os.environ["APPDATA"], "Electrum-Zcash")
elif "LOCALAPPDATA" in os.environ: elif "LOCALAPPDATA" in os.environ:
return os.path.join(os.environ["LOCALAPPDATA"], "Electrum") return os.path.join(os.environ["LOCALAPPDATA"], "Electrum-Zcash")
else: else:
#raise Exception("No home directory found in environment variables.") #raise Exception("No home directory found in environment variables.")
return return
@ -421,36 +429,14 @@ def time_difference(distance_in_time, include_seconds):
return "over %d years" % (round(distance_in_minutes / 525600)) return "over %d years" % (round(distance_in_minutes / 525600))
mainnet_block_explorers = { mainnet_block_explorers = {
'Biteasy.com': ('https://www.biteasy.com/blockchain', 'blockexplorer.com': ('https://zcash.blockexplorer.com/blocks',
{'tx': 'transactions', 'addr': 'addresses'}), {'tx': 'transactions', 'addr': 'addresses'}),
'Bitflyer.jp': ('https://chainflyer.bitflyer.jp',
{'tx': 'Transaction', 'addr': 'Address'}),
'Blockchain.info': ('https://blockchain.info',
{'tx': 'tx', 'addr': 'address'}),
'blockchainbdgpzk.onion': ('https://blockchainbdgpzk.onion',
{'tx': 'tx', 'addr': 'address'}),
'Blockr.io': ('https://btc.blockr.io',
{'tx': 'tx/info', 'addr': 'address/info'}),
'Blocktrail.com': ('https://www.blocktrail.com/BTC',
{'tx': 'tx', 'addr': 'address'}),
'BTC.com': ('https://chain.btc.com',
{'tx': 'tx', 'addr': 'address'}),
'Chain.so': ('https://www.chain.so',
{'tx': 'tx/BTC', 'addr': 'address/BTC'}),
'Insight.is': ('https://insight.bitpay.com',
{'tx': 'tx', 'addr': 'address'}),
'TradeBlock.com': ('https://tradeblock.com/blockchain',
{'tx': 'tx', 'addr': 'address'}),
'BlockCypher.com': ('https://live.blockcypher.com/btc',
{'tx': 'tx', 'addr': 'address'}),
'Blockchair.com': ('https://blockchair.com/bitcoin',
{'tx': 'transaction', 'addr': 'address'}),
'system default': ('blockchain:', 'system default': ('blockchain:',
{'tx': 'tx', 'addr': 'address'}), {'tx': 'tx', 'addr': 'address'}),
} }
testnet_block_explorers = { testnet_block_explorers = {
'Blocktrail.com': ('https://www.blocktrail.com/tBTC', 'testnet.z.cash': ('https://explorer.testnet.z.cash/',
{'tx': 'tx', 'addr': 'address'}), {'tx': 'tx', 'addr': 'address'}),
'system default': ('blockchain:', 'system default': ('blockchain:',
{'tx': 'tx', 'addr': 'address'}), {'tx': 'tx', 'addr': 'address'}),
@ -461,7 +447,7 @@ def block_explorer_info():
return testnet_block_explorers if bitcoin.NetworkConstants.TESTNET else mainnet_block_explorers return testnet_block_explorers if bitcoin.NetworkConstants.TESTNET else mainnet_block_explorers
def block_explorer(config): def block_explorer(config):
return config.get('block_explorer', 'Blocktrail.com') return config.get('block_explorer', 'blockexplorer.com')
def block_explorer_tuple(config): def block_explorer_tuple(config):
return block_explorer_info().get(block_explorer(config)) return block_explorer_info().get(block_explorer(config))
@ -486,12 +472,12 @@ def parse_URI(uri, on_pr=None):
if ':' not in uri: if ':' not in uri:
if not bitcoin.is_address(uri): if not bitcoin.is_address(uri):
raise BaseException("Not a bitcoin address") raise BaseException("Not a Zcash address")
return {'address': uri} return {'address': uri}
u = urllib.parse.urlparse(uri) u = urllib.parse.urlparse(uri)
if u.scheme != 'bitcoin': if u.scheme != 'zcash':
raise BaseException("Not a bitcoin URI") raise BaseException("Not a Zcash URI")
address = u.path address = u.path
# python for android fails to parse query # python for android fails to parse query
@ -508,7 +494,7 @@ def parse_URI(uri, on_pr=None):
out = {k: v[0] for k, v in pq.items()} out = {k: v[0] for k, v in pq.items()}
if address: if address:
if not bitcoin.is_address(address): if not bitcoin.is_address(address):
raise BaseException("Invalid bitcoin address:" + address) raise BaseException("Invalid Zcash address:" + address)
out['address'] = address out['address'] = address
if 'amount' in out: if 'amount' in out:
am = out['amount'] am = out['amount']
@ -558,7 +544,7 @@ def create_URI(addr, amount, message):
query.append('amount=%s'%format_satoshis_plain(amount)) query.append('amount=%s'%format_satoshis_plain(amount))
if message: if message:
query.append('message=%s'%urllib.parse.quote(message)) query.append('message=%s'%urllib.parse.quote(message))
p = urllib.parse.ParseResult(scheme='bitcoin', netloc='', path=addr, params='', query='&'.join(query), fragment='') p = urllib.parse.ParseResult(scheme='zcash', netloc='', path=addr, params='', query='&'.join(query), fragment='')
return urllib.parse.urlunparse(p) return urllib.parse.urlunparse(p)

View File

@ -3,11 +3,8 @@ PROTOCOL_VERSION = '1.1' # protocol version requested
# The hash of the mnemonic seed must begin with this # The hash of the mnemonic seed must begin with this
SEED_PREFIX = '01' # Standard wallet SEED_PREFIX = '01' # Standard wallet
SEED_PREFIX_2FA = '101' # Two-factor authentication
def seed_prefix(seed_type): def seed_prefix(seed_type):
if seed_type == 'standard': if seed_type == 'standard':
return SEED_PREFIX return SEED_PREFIX
elif seed_type == '2fa':
return SEED_PREFIX_2FA

View File

@ -69,8 +69,8 @@ TX_STATUS = [
def relayfee(network): def relayfee(network):
RELAY_FEE = 5000 RELAY_FEE = 1000
MAX_RELAY_FEE = 50000 MAX_RELAY_FEE = 10000
f = network.relay_fee if network and network.relay_fee else RELAY_FEE f = network.relay_fee if network and network.relay_fee else RELAY_FEE
return min(f, MAX_RELAY_FEE) return min(f, MAX_RELAY_FEE)
@ -868,7 +868,7 @@ class Abstract_Wallet(PrintError):
_type, data, value = o _type, data, value = o
if _type == TYPE_ADDRESS: if _type == TYPE_ADDRESS:
if not is_address(data): if not is_address(data):
raise BaseException("Invalid bitcoin address:" + data) raise BaseException("Invalid Zcash address:" + data)
if value == '!': if value == '!':
if i_max is not None: if i_max is not None:
raise BaseException("More than one output set to spend max") raise BaseException("More than one output set to spend max")
@ -1199,7 +1199,7 @@ class Abstract_Wallet(PrintError):
if not r: if not r:
return return
out = copy.copy(r) out = copy.copy(r)
out['URI'] = 'bitcoin:' + addr + '?amount=' + format_satoshis(out.get('amount')) out['URI'] = 'zcash:' + addr + '?amount=' + format_satoshis(out.get('amount'))
status, conf = self.get_request_status(addr) status, conf = self.get_request_status(addr)
out['status'] = status out['status'] = status
if conf is not None: if conf is not None:

View File

@ -32,9 +32,9 @@ if (id) {
.done( function(data) { .done( function(data) {
new QRCode(document.getElementById("qrcode"), data.URI); new QRCode(document.getElementById("qrcode"), data.URI);
$("<p />").text(data.memo).appendTo($("p#reason")); $("<p />").text(data.memo).appendTo($("p#reason"));
$("<p />").text(data.amount/100000000 + "BTC").appendTo($("p#amount")); $("<p />").text(data.amount/100000000 + "ZEC").appendTo($("p#amount"));
$("a").attr("href", data.URI); $("a").attr("href", data.URI);
$("<p />").text("Powered by Electrum").appendTo($("p#powered")); $("<p />").text("Powered by Electrum-Zcash").appendTo($("p#powered"));
var websocket_server = data.websocket_server; var websocket_server = data.websocket_server;
var websocket_port = data.websocket_port; var websocket_port = data.websocket_port;
$(function () { $(function () {
@ -84,10 +84,10 @@ if (id) {
}; };
// See http://stackoverflow.com/questions/29186154/chrome-clicking-mailto-links-closes-websocket-connection // See http://stackoverflow.com/questions/29186154/chrome-clicking-mailto-links-closes-websocket-connection
$(document).on('click', 'a[href^="bitcoin:"]', function (e) { $(document).on('click', 'a[href^="zcash:"]', function (e) {
e.preventDefault(); e.preventDefault();
var btcWindow = window.open($(e.currentTarget).attr('href')); var zcashWindow = window.open($(e.currentTarget).attr('href'));
btcWindow.close(); zcashWindow.close();
return false; return false;
}); });
@ -99,7 +99,7 @@ $(document).on('click', 'a[href^="bitcoin:"]', function (e) {
<p id="reason"></p> <p id="reason"></p>
<p id="amount"></p> <p id="amount"></p>
<div style="background-color:#7777aa; border-radius: 5px; padding:10px;"> <div style="background-color:#7777aa; border-radius: 5px; padding:10px;">
<a style="color:#ffffff; text-decoration:none;" id="paylink" target="_blank">Pay with Bitcoin</a> <a style="color:#ffffff; text-decoration:none;" id="paylink" target="_blank">Pay with Zcash</a>
</div> </div>
<br/> <br/>
<div id="qrcode" align="center"></div> <div id="qrcode" align="center"></div>