├── lib ├── tests │ ├── __init__.py │ ├── test_chains_base58.py │ ├── test_chainparams.py │ ├── test_util.py │ └── test_wallet.py ├── chains │ ├── __init__.py │ ├── cryptocur.py │ └── README.md ├── version.py ├── __init__.py ├── qrscanner.py ├── i18n.py ├── paymentrequest.proto ├── msqr.py ├── chainparams.py ├── plugins.py └── mnemonic.py ├── data ├── dark │ ├── name.cfg │ └── style.css ├── sahara │ ├── name.cfg │ └── style.css ├── cleanlook │ ├── name.cfg │ └── style.css └── README ├── plugins ├── __init__.py ├── virtualkeyboard.py ├── greenaddress_instant.py └── plot.py ├── requirements.txt ├── contrib ├── encompass-release │ ├── helpers │ │ ├── packages │ │ │ └── google │ │ │ │ └── __init__.py │ │ ├── darkcoin_hash-build.bat │ │ ├── ltc_scrypt-build.bat │ │ ├── encompass_linux_startup.sh │ │ ├── hidapi-build.bat │ │ ├── make_commands_list │ │ ├── requirements.txt │ │ ├── build-hidapi.sh │ │ ├── setup.py-ltc_scrypt-1.0 │ │ ├── setup.py-SocksiPy-branch-1.01 │ │ ├── wip │ │ │ ├── fix_OSX-pyinstaller.sh │ │ │ ├── OSX-cross │ │ │ │ ├── build-darwin-ltc_scrypt.sh │ │ │ │ └── build-darwin-darkcoin_hash.sh │ │ │ └── build_osx-pyinstaller.sh │ │ ├── build-binary │ │ ├── build_osx.sh │ │ ├── setup.py-darkcoin_hash-1.1 │ │ ├── make_android │ │ ├── make_packages │ │ ├── make_windows │ │ ├── 90-trezor.rules │ │ ├── make_linux │ │ ├── make_OSX-installer.sh │ │ ├── make_locale │ │ ├── make_release │ │ └── linux_installer.in │ ├── Dockerfile-32Bit │ ├── Dockerfile-release │ ├── clean.sh │ ├── source │ │ ├── deterministic.spec │ │ ├── linux.spec │ │ ├── osx.spec │ │ └── encompass.nsi │ ├── Makefile.in │ ├── Dockerfile │ └── README.md ├── ArchLinux │ └── encompass-git │ │ ├── encompass.install │ │ ├── .SRCINFO │ │ └── PKGBUILD └── make_download ├── encompass.icns ├── icons ├── key.png ├── lock.png ├── seed.png ├── clock1.png ├── clock2.png ├── clock3.png ├── clock4.png ├── clock5.png ├── network.png ├── qrcode.png ├── unlock.png ├── cold_seed.png ├── confirmed.png ├── encompass.ico ├── encompass.png ├── hot_seed.png ├── switchgui.png ├── preferences.png ├── trustedcoin.png ├── unconfirmed.png ├── encompass-logo.jpg ├── status_lagging.png ├── status_waiting.png ├── dark_background.png ├── status_connected.png ├── electrum_dark_icon.png ├── electrum_light_icon.png └── status_disconnected.png ├── gui ├── __init__.py └── qt │ ├── history_widget.py │ ├── qrtextedit.py │ ├── qrwindow.py │ ├── receiving_widget.py │ ├── amountedit.py │ ├── qrcodewidget.py │ ├── seed_dialog.py │ └── version_getter.py ├── .travis.yml ├── scripts ├── get_history ├── txradar ├── merchant │ ├── merchant.conf.template │ └── merchant.readme ├── servers ├── block_headers ├── watch_address ├── peers └── util.py ├── app.fil ├── .gitignore ├── MANIFEST.in ├── encompass.desktop ├── encompass.conf.sample ├── Info.plist ├── AUTHORS ├── README-Windows.md ├── README ├── icons.qrc ├── README-Linux-x86_64.md ├── README-ArchLinux.md ├── README-OSX.md ├── CONTRIBUTING.md ├── RELEASE-NOTES ├── mki18n.py ├── docs ├── cold_storage ├── android.html └── console.html ├── README-source.md ├── setup-release.py ├── pubkeys └── mazaclub.asc └── setup.py /lib/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/dark/name.cfg: -------------------------------------------------------------------------------- 1 | Dark 2 | -------------------------------------------------------------------------------- /data/sahara/name.cfg: -------------------------------------------------------------------------------- 1 | Sahara 2 | -------------------------------------------------------------------------------- /plugins/__init__.py: -------------------------------------------------------------------------------- 1 | # plugins 2 | -------------------------------------------------------------------------------- /data/cleanlook/name.cfg: -------------------------------------------------------------------------------- 1 | Cleanlook 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | contrib/encompass-release/helpers/requirements.txt -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/packages/google/__init__.py: -------------------------------------------------------------------------------- 1 | import google 2 | -------------------------------------------------------------------------------- /encompass.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/encompass.icns -------------------------------------------------------------------------------- /icons/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/key.png -------------------------------------------------------------------------------- /icons/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/lock.png -------------------------------------------------------------------------------- /icons/seed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/seed.png -------------------------------------------------------------------------------- /icons/clock1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/clock1.png -------------------------------------------------------------------------------- /icons/clock2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/clock2.png -------------------------------------------------------------------------------- /icons/clock3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/clock3.png -------------------------------------------------------------------------------- /icons/clock4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/clock4.png -------------------------------------------------------------------------------- /icons/clock5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/clock5.png -------------------------------------------------------------------------------- /icons/network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/network.png -------------------------------------------------------------------------------- /icons/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/qrcode.png -------------------------------------------------------------------------------- /icons/unlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/unlock.png -------------------------------------------------------------------------------- /icons/cold_seed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/cold_seed.png -------------------------------------------------------------------------------- /icons/confirmed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/confirmed.png -------------------------------------------------------------------------------- /icons/encompass.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/encompass.ico -------------------------------------------------------------------------------- /icons/encompass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/encompass.png -------------------------------------------------------------------------------- /icons/hot_seed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/hot_seed.png -------------------------------------------------------------------------------- /icons/switchgui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/switchgui.png -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/darkcoin_hash-build.bat: -------------------------------------------------------------------------------- 1 | cd Z:\code 2 | python setup.py build 3 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/ltc_scrypt-build.bat: -------------------------------------------------------------------------------- 1 | cd Z:\code 2 | python setup.py build 3 | -------------------------------------------------------------------------------- /icons/preferences.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/preferences.png -------------------------------------------------------------------------------- /icons/trustedcoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/trustedcoin.png -------------------------------------------------------------------------------- /icons/unconfirmed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/unconfirmed.png -------------------------------------------------------------------------------- /icons/encompass-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/encompass-logo.jpg -------------------------------------------------------------------------------- /icons/status_lagging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/status_lagging.png -------------------------------------------------------------------------------- /icons/status_waiting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/status_waiting.png -------------------------------------------------------------------------------- /icons/dark_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/dark_background.png -------------------------------------------------------------------------------- /icons/status_connected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/status_connected.png -------------------------------------------------------------------------------- /icons/electrum_dark_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/electrum_dark_icon.png -------------------------------------------------------------------------------- /icons/electrum_light_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/electrum_light_icon.png -------------------------------------------------------------------------------- /icons/status_disconnected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazaclub/encompass/HEAD/icons/status_disconnected.png -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/encompass_linux_startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DIR=INSTALL_DIR 3 | cd $DIR/encompass 4 | ./encompass-x86_64.bin 5 | 6 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/hidapi-build.bat: -------------------------------------------------------------------------------- 1 | cd Z:\wine\wine-py2.7.8-32\drive_c\Python27\Scripts 2 | python pip.exe install cython 3 | cd Z:\code 4 | python setup.py build 5 | -------------------------------------------------------------------------------- /lib/chains/__init__.py: -------------------------------------------------------------------------------- 1 | import cryptocur 2 | import bitcoin, mazacoin 3 | import ltc_scrypt 4 | import scrypt 5 | import litecoin 6 | import viacoin 7 | import dash 8 | #__all__ = ['cryptocur, bitcoin, mazacoin'] 9 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/make_commands_list: -------------------------------------------------------------------------------- 1 | cat lib/commands.py|grep register_command|sed "s/register_command(\(.*\))/\1/" |sed "s/'//g"| awk -F, '{print "|-\n|" $1 "|| " $7 "|| " $8 "|| " $4 "|| " $5 "|| " $6 }' 2 | -------------------------------------------------------------------------------- /gui/__init__.py: -------------------------------------------------------------------------------- 1 | # To create a new GUI, please add its code to this directory. 2 | # Two objects must be passed to the ElectrumGui: config and network 3 | # The Wallet object is instanciated by the GUI 4 | 5 | # Notifications about network events are sent to the GUI by using network.register_callback() 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | install: 5 | - pip install slowaes==0.1a1 ecdsa>=0.9 pbkdf2 requests pyasn1 pyasn1-modules tlslite>=0.4.5 qrcode SocksiPy-branch ltc_scrypt 6 | - git clone https://github.com/guruvan/darkcoin_hash 7 | - cd darkcoin_hash 8 | - git checkout 1.1 9 | - python setup.py install 10 | - cd .. 11 | script: nosetests -e gui 12 | -------------------------------------------------------------------------------- /scripts/get_history: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | from chainkey import NetworkProxy, print_json 5 | 6 | try: 7 | addr = sys.argv[1] 8 | except Exception: 9 | print "usage: get_history " 10 | sys.exit(1) 11 | 12 | n = NetworkProxy() 13 | n.start(start_daemon=True) 14 | h = n.synchronous_get([ ('blockchain.address.get_history',[addr]) ])[0] 15 | print_json(h) 16 | 17 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/requirements.txt: -------------------------------------------------------------------------------- 1 | slowaes==0.1a1 2 | ecdsa==0.13 3 | pbkdf2==1.3 4 | requests==2.5.1 5 | pyasn1-modules==0.0.5 6 | pyasn1==0.1.7 7 | qrcode==5.1 8 | SocksiPy-branch==1.01 9 | tlslite==0.4.8 10 | hidapi>=0.7.99 11 | protobuf==2.5.0 12 | mnemonic>=0.8 13 | ltc_scrypt==1.0 14 | git+https://github.com/guruvan/darkcoin_hash#egg=darkcoin_hash 15 | git+https://github.com/mazaclub/python-trezor#egg=trezor 16 | -------------------------------------------------------------------------------- /lib/version.py: -------------------------------------------------------------------------------- 1 | ELECTRUM_VERSION = "0.5.0" # version of the client package 2 | PROTOCOL_VERSION = '0.9' # protocol version requested 3 | NEW_SEED_VERSION = 10 # electrum versions >= 2.0 4 | OLD_SEED_VERSION = 4 # electrum versions < 2.0 5 | 6 | 7 | # The hash of the mnemonic seed must begin with this 8 | SEED_BIP44 = '01' # BIP44 9 | SEED_2FA = '101' # extended seed for two-factor authentication 10 | -------------------------------------------------------------------------------- /contrib/ArchLinux/encompass-git/encompass.install: -------------------------------------------------------------------------------- 1 | post_install() { 2 | [[ -x /usr/bin/update-desktop-database ]] && update-desktop-database -q 3 | [[ -x /usr/bin/xdg-icon-resource ]] && xdg-icon-resource forceupdate --theme hicolor 4 | [[ -x /usr/bin/gtk-update-icon-cache ]] && gtk-update-icon-cache -f -q /usr/share/icons/hicolor 5 | } 6 | 7 | post_upgrade() { 8 | post_install 9 | } 10 | 11 | post_remove() { 12 | post_install 13 | } 14 | -------------------------------------------------------------------------------- /app.fil: -------------------------------------------------------------------------------- 1 | gui/gtk.py 2 | gui/qt/main_window.py 3 | gui/qt/lite_window.py 4 | gui/qt/history_widget.py 5 | gui/qt/installwizard.py 6 | gui/qt/network_dialog.py 7 | gui/qt/password_dialog.py 8 | gui/qt/util.py 9 | gui/qt/receiving_widget.py 10 | gui/qt/seed_dialog.py 11 | gui/qt/transaction_dialog.py 12 | gui/qt/version_getter.py 13 | plugins/aliases.py 14 | plugins/pointofsale.py 15 | plugins/labels.py 16 | plugins/qrscanner.py 17 | plugins/virtualkeyboard.py 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | releases/* 2 | source/*.tar.gz 3 | source/encompass-* 4 | source/Encompass-* 5 | .present 6 | contrib/encompass-release/repo/* 7 | *.pyc 8 | *.pyd 9 | *.swp 10 | *.so 11 | *.dylib 12 | *.pyd 13 | gui/qt/icons_rc.py 14 | contrib/encompass-release/repo/ 15 | contrib/encompass-release/source/Encompas-* 16 | contrib/encompass-release/source/encompas-* 17 | contrib/encompass-release/ltc_scrypt-1.0/ 18 | contrib/encompass-release/ltc_scrypt-1.0* 19 | *.pydev* 20 | 1 21 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/build-hidapi.sh: -------------------------------------------------------------------------------- 1 | git clone https://github.com/trezor/cython-hidapi 2 | cd cython-hidapi 3 | git submodule init 4 | git submodule update 5 | cd .. 6 | docker run --privileged -ti --rm \ 7 | -e WINEPREFIX="/wine/wine-py2.7.8-32" \ 8 | -v $(pwd)/cython-hidapi:/code \ 9 | -v $(pwd)/helpers:/helpers \ 10 | ogrisel/python-winbuilder wineconsole --backend=curses Z:\\helpers\\hidapi-build.bat 11 | cp -av cython-hidapi/build/lib.win32-2.7/hid.pyd ./helpers 12 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README LICENCE RELEASE-NOTES AUTHORS 2 | include encompass.conf.sample 3 | include encompass.desktop 4 | include *.py 5 | include encompass 6 | recursive-include lib *.py 7 | recursive-include gui *.py 8 | recursive-include plugins *.py 9 | recursive-include packages *.py 10 | include app.fil 11 | include icons.qrc 12 | include *.pem 13 | recursive-include icons * 14 | recursive-include scripts * 15 | recursive-include data * 16 | recursive-include locale *.mo 17 | recursive-include docs * 18 | 19 | -------------------------------------------------------------------------------- /scripts/txradar: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import util, sys 3 | try: 4 | tx = sys.argv[1] 5 | except: 6 | print "usage: txradar txid" 7 | sys.exit(1) 8 | 9 | peers = util.get_peers() 10 | results = util.send_request(peers, {'method':'blockchain.transaction.get','params':[tx]}) 11 | 12 | r1 = [] 13 | r2 = [] 14 | 15 | for k, v in results.items(): 16 | (r1 if v else r2).append(k) 17 | 18 | print "Received %d answers"%len(results) 19 | print "Propagation rate: %.1f percent" % (len(r1) *100./(len(r1)+ len(r2))) 20 | 21 | -------------------------------------------------------------------------------- /contrib/encompass-release/Dockerfile-32Bit: -------------------------------------------------------------------------------- 1 | FROM ubuntu-32bit:14.04 2 | MAINTAINER Rob Nelson 3 | ENV BUILDER_VER 1.1 4 | 5 | VOLUME ["/opt/wine-electrum/drive_c/encompass"] 6 | 7 | RUN apt-get update -y \ 8 | && apt-get install -y software-properties-common curl wget \ 9 | git python-pip pyqt4-dev-tools zip unzip python-dev \ 10 | python-all python-all-dev debhelper \ 11 | && pip install stdeb \ 12 | && apt-get purge -y python-software-properties \ 13 | && apt-get autoclean -y 14 | 15 | 16 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/setup.py-ltc_scrypt-1.0: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | import os 3 | del os.link 4 | ltc_scrypt_module = Extension('ltc_scrypt', 5 | sources=['./scryptmodule.c', 6 | './scrypt.c'], 7 | include_dirs=['./ltc_scrypt','./']) 8 | 9 | setup(name='ltc_scrypt', 10 | version='1.0', 11 | description='Bindings for scrypt proof of work used by Litecoin', 12 | ext_modules=[ltc_scrypt_module]) 13 | -------------------------------------------------------------------------------- /encompass.desktop: -------------------------------------------------------------------------------- 1 | # If you want electrum to appear in a linux app launcher ("start menu"), install this by doing: 2 | # sudo desktop-file-install electrum.desktop 3 | 4 | [Desktop Entry] 5 | Comment=Lightweight Multi-Coin Client 6 | Exec=encompass %u 7 | GenericName[en_US]=Encompass 8 | GenericName=Encompass 9 | Icon=/usr/share/app-install/icons/encompass.png 10 | Name[en_US]=Encompass Multi-Coin Wallet 11 | Name=Encompass Multi-Coin Wallet 12 | Categories=Network; 13 | StartupNotify=false 14 | Terminal=false 15 | Type=Application 16 | MimeType=x-scheme-handler/bitcoin 17 | 18 | -------------------------------------------------------------------------------- /scripts/merchant/merchant.conf.template: -------------------------------------------------------------------------------- 1 | [main] 2 | host = hostname of the machine where you run this program 3 | port = choose a port number 4 | password = choose a password 5 | 6 | [sqlite3] 7 | database = database filename 8 | 9 | [electrum] 10 | xpub = the master public key of your wallet 11 | wallet_path = path where the script will save the wallet 12 | 13 | [callback] 14 | received = URL where we POST json data when payment has been received 15 | expired = URL where we POST json data if payment has expired 16 | password = password sent in the json data, for authentication 17 | -------------------------------------------------------------------------------- /encompass.conf.sample: -------------------------------------------------------------------------------- 1 | # Configuration file for the electrum client 2 | # Settings defined here are shared across wallets 3 | # 4 | # copy this file to /etc/electrum.conf if you want read-only settings 5 | # copy it into your ~/.electrum/ directory if you want global settings 6 | # that can be rewritten by the client 7 | 8 | [client] 9 | server = electrum.novit.ro:50001:t 10 | proxy = None 11 | gap_limit = 5 12 | # booleans use python syntax 13 | use_change = True 14 | gui = qt 15 | num_zeros = 2 16 | # default transaction fee is in Satoshis 17 | fee = 10000 18 | winpos-qt = [799, 226, 877, 435] 19 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/setup.py-SocksiPy-branch-1.01: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from distutils.core import setup 3 | import os 4 | del os.link 5 | 6 | VERSION = "1.01" 7 | 8 | setup( 9 | name = "SocksiPy-branch", 10 | version = VERSION, 11 | description = "A Python SOCKS module", 12 | long_description = "This Python module allows you to create TCP connections through a SOCKS proxy without any special effort.", 13 | url = "http://socksipy.sourceforge.net/", 14 | author = "Dan-Haim", 15 | author_email="negativeiq@users.sourceforge.net", 16 | license = "BSD", 17 | py_modules=["socks"] 18 | ) 19 | 20 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleURLTypes 6 | 7 | 8 | CFBundleURLName 9 | bitcoin 10 | CFBundleURLSchemes 11 | 12 | bitcoin 13 | 14 | 15 | 16 | LSArchitecturePriority 17 | 18 | x86_64 19 | i386 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /data/README: -------------------------------------------------------------------------------- 1 | To add a new theme, simply create a new directory in the electrum data directory (either ./data or your system wide local data). 2 | 3 | Inside your directory create a file called name.cfg with the name of that theme. 4 | 5 | Create another file called style.css - this will be your CSS for the theme (see other themes for reference). 6 | 7 | Documentation on Qt's stylesheets (used by Electrum): 8 | 9 | Overview: http://qt-project.org/doc/qt-4.8/stylesheet.html 10 | Examples: http://qt-project.org/doc/qt-4.8/stylesheet-examples.html 11 | Reference manual: http://doc.qt.nokia.com/4.7-snapshot/stylesheet-reference.html 12 | 13 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | ThomasV - Original Electrum Creator and maintainer. 2 | Kefkius - Encompass Creator - Multi-coin support using one wallet seed 3 | Animazing / Tachikoma - Styled the new GUI. Mac version. 4 | Azelphur - GUI stuff. 5 | Coblee - Alternate coin support and py2app support. 6 | Deafboy - Ubuntu packages. 7 | EagleTM - Bugfixes. 8 | ErebusBat - Mac distribution. 9 | Genjix - Porting pro-mode functionality to lite-gui and worked on server 10 | Slush - Work on the server. Designed the original Stratum spec. 11 | Julian Toash (Tuxavant) - Various fixes to the client. 12 | rdymac - Website and translations. 13 | guruvan - build/release system improvements 14 | -------------------------------------------------------------------------------- /data/dark/style.css: -------------------------------------------------------------------------------- 1 | #main_window 2 | { 3 | background-image: url(:/icons/dark_background.png); 4 | } 5 | 6 | #address_input[readOnly=true], #amount_input[readOnly=true] 7 | { 8 | font: italic; 9 | color: gray; 10 | } 11 | #address_input[readOnly=false], #amount_input[readOnly=false] 12 | { 13 | font: normal; 14 | color: black; 15 | } 16 | 17 | #valid_address::indicator 18 | { 19 | width: 24px; 20 | height: 24px; 21 | } 22 | #valid_address::indicator:checked 23 | { 24 | image: url(confirmed.png); 25 | } 26 | #valid_address::indicator:unchecked 27 | { 28 | image: url(unconfirmed.png); 29 | } 30 | 31 | #balance_label 32 | { 33 | color: white; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/wip/fix_OSX-pyinstaller.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | distdir=./helpers/release-packages/OSX/Encompass.app 4 | qtdir=/Developer/Applications/Qt 5 | 6 | cat > ${distdir}/Contents/Resources/qt.conf < 3 | ENV BUILDER_VER 1.2 4 | 5 | VOLUME ["/opt/wine-electrum/drive_c/encompass"] 6 | 7 | RUN apt-get update -y 8 | RUN apt-get install -y software-properties-common curl wget \ 9 | git python-pip pyqt4-dev-tools zip unzip python-dev \ 10 | python-all python-all-dev debhelper \ 11 | cython libusb-1.0-0-dev libudev-dev 12 | RUN pip install stdeb 13 | RUN git clone https://github.com/pyinstaller/pyinstaller \ 14 | && cd pyinstaller \ 15 | && python setup.py install 16 | RUN adduser --disabled-password --gecos "build" build 17 | RUN apt-get purge -y python-software-properties 18 | RUN apt-get autoclean -y 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- 1 | from version import ELECTRUM_VERSION 2 | from util import format_satoshis, print_msg, print_json, print_error, set_verbosity 3 | from wallet import WalletSynchronizer, WalletStorage 4 | from wallet import Wallet, Wallet_2of2, Wallet_2of3, Imported_Wallet 5 | from verifier import TxVerifier 6 | from network import Network, DEFAULT_SERVERS, DEFAULT_PORTS, pick_random_server 7 | from interface import Interface 8 | from simple_config import SimpleConfig, get_config, set_config 9 | import bitcoin 10 | import account 11 | import transaction 12 | from transaction import Transaction 13 | from plugins import BasePlugin 14 | from commands import Commands, known_commands 15 | from daemon import NetworkServer 16 | from network_proxy import NetworkProxy 17 | import chainparams 18 | -------------------------------------------------------------------------------- /scripts/servers: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from chainkey import Interface, SimpleConfig, set_verbosity 4 | from chainkey.network import DEFAULT_SERVERS, filter_protocol 5 | import time, Queue 6 | from collections import defaultdict 7 | 8 | import util, json 9 | set_verbosity(False) 10 | 11 | config = SimpleConfig() 12 | servers = filter_protocol(DEFAULT_SERVERS,'t') 13 | results = util.send_request(servers, {'method':'blockchain.headers.subscribe', 'params':[]}) 14 | 15 | d = defaultdict(int) 16 | 17 | for k, r in results.items(): 18 | blocks = r.get('block_height') 19 | d[blocks] += 1 20 | 21 | 22 | 23 | for k, v in results.items(): 24 | print k, v.get('block_height') 25 | 26 | v = d.values() 27 | numblocks = d.keys()[v.index(max(v))] 28 | print "blocks:",numblocks 29 | -------------------------------------------------------------------------------- /scripts/block_headers: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # A simple script that connects to a server and displays block headers 4 | 5 | import time 6 | import chainkey 7 | 8 | # start network 9 | c = electrum.SimpleConfig() 10 | s = electrum.daemon.get_daemon(c,True) 11 | network = electrum.NetworkProxy(s,c) 12 | network.start() 13 | 14 | # wait until connected 15 | while network.is_connecting(): 16 | time.sleep(0.1) 17 | 18 | if not network.is_connected(): 19 | print_msg("daemon is not connected") 20 | sys.exit(1) 21 | 22 | # 2. send the subscription 23 | callback = lambda response: electrum.print_json(response.get('result')) 24 | network.send([('blockchain.headers.subscribe',[])], callback) 25 | 26 | # 3. wait for results 27 | while network.is_connected(): 28 | time.sleep(1) 29 | 30 | -------------------------------------------------------------------------------- /scripts/watch_address: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import time 5 | import chainkey 6 | 7 | try: 8 | addr = sys.argv[1] 9 | except Exception: 10 | print "usage: watch_address " 11 | sys.exit(1) 12 | 13 | # start network 14 | c = electrum.SimpleConfig() 15 | s = electrum.daemon.get_daemon(c,True) 16 | network = electrum.NetworkProxy(s,c) 17 | network.start() 18 | 19 | # wait until connected 20 | while network.is_connecting(): 21 | time.sleep(0.1) 22 | 23 | if not network.is_connected(): 24 | print_msg("daemon is not connected") 25 | sys.exit(1) 26 | 27 | # 2. send the subscription 28 | callback = lambda response: electrum.print_json(response.get('result')) 29 | network.send([('blockchain.address.subscribe',[addr])], callback) 30 | 31 | # 3. wait for results 32 | while network.is_connected(): 33 | time.sleep(1) 34 | 35 | -------------------------------------------------------------------------------- /gui/qt/history_widget.py: -------------------------------------------------------------------------------- 1 | from PyQt4.QtGui import * 2 | from chainkey.i18n import _ 3 | 4 | class HistoryWidget(QTreeWidget): 5 | 6 | def __init__(self, parent=None): 7 | QTreeWidget.__init__(self, parent) 8 | self.setColumnCount(2) 9 | self.setHeaderLabels([_("Amount"), _("To / From"), _("When")]) 10 | self.setIndentation(0) 11 | 12 | def empty(self): 13 | self.clear() 14 | 15 | def append(self, address, amount, date): 16 | if address is None: 17 | address = _("Unknown") 18 | if amount is None: 19 | amount = _("Unknown") 20 | if date is None: 21 | date = _("Unknown") 22 | item = QTreeWidgetItem([amount, address, date]) 23 | if float(amount) < 0: 24 | item.setForeground(0, QBrush(QColor("#BC1E1E"))) 25 | self.insertTopLevelItem(0, item) 26 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/wip/OSX-cross/build-darwin-ltc_scrypt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd /code 4 | mkdir -pv build/temp.darwin-x64 5 | mkdir -pv build/lib.darwin-x64 6 | 7 | 8 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I./ltc_scrypt -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c ./scryptmodule.c -o build/temp.darwin-x64/./scryptmodule.o 9 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I./ltc_scrypt -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c ./scrypt.c -o build/temp.darwin-x64/./scrypt.o 10 | x86_64-apple-darwin14-cc -shared -lpython -L/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/lib/ -L/usr/x86_64-apple-darwin14/lib -L/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/libexec/ build/temp.darwin-x64/./scryptmodule.o build/temp.darwin-x64/./scrypt.o -o build/lib.darwin-x64/ltc_scrypt.dylib 11 | 12 | -------------------------------------------------------------------------------- /README-Windows.md: -------------------------------------------------------------------------------- 1 | Encompass - lightweight multi-coin client 2 | 3 | Encompass consolidates support for various currencies into one wallet. It is a BIP-0044-compliant multi-currency wallet based on Electrum. This Encompass client uses Electrum servers of supported currencies to retrieve necessary data, so no "Encompass server" is necessary. 4 | 5 | Homepage: https://maza.club/encompass 6 | 7 | 1. ENCOMPASS ON WINDOWS 8 | ----------------------- 9 | 10 | - Simply download the provided Encompass-0.5.0-setup.exe and run 11 | 12 | Your Wallet files will be in one of the following places, based on the version of Windows installed: 13 | - C:\Users\YOUR_LOGIN_NAME\Application Data\Encompass\wallets 14 | - 15 | 16 | 17 | 18 | 2. HOW OFFICIAL PACKAGES ARE CREATED 19 | ------------------------------------ 20 | 21 | See contrib/encompass-release/README.md 22 | 23 | 3. HOW COIN-SPECIFIC MODULES ARE CREATED 24 | ---------------------------------------- 25 | 26 | See lib/chains/README.md. 27 | -------------------------------------------------------------------------------- /contrib/encompass-release/clean.sh: -------------------------------------------------------------------------------- 1 | USER=$(whoami) 2 | HOST=$(uname) 3 | if [ "$HOST" = "Darwin" ] 4 | then 5 | GROUP="$(groups |awk '{print $1}')" 6 | else 7 | GROUP=${USER} 8 | fi 9 | sudo chown -R ${USER}:${GROUP} . 10 | rm -rf releases/* 11 | rm -rf source/Encompass* 12 | rm -rf source/encompass-setup.exe 13 | rm -rf repo 14 | rm -rf ltc_scrypt* 15 | rm -rf helpers/release-packages 16 | rm -rf helpers/*.dylib 17 | rm -rf helpers/*.so 18 | rm -rf helpers/*.pyd 19 | rm -rf helpers/.??* 20 | rm -rf helpers/linux_installer.sh 21 | rm -rf 1.1.tar.gz* 22 | rm -rf darkcoin_hash* 23 | rm -rf groestlcoin* 24 | rm -rf SocksiPy* 25 | rm -rf helpers/.??* 26 | rm -rf helpers/repo 27 | rm -rf helpers/encompass-release 28 | rm -rf src Encompass-*.dmg 29 | rm -rf Makefile 30 | rm -rf helpers/debian_installer.sh 31 | rm -rf helpers/trezorctl.py 32 | rm -rf cython-hidapi 33 | rm -rf python-trezor 34 | 35 | if [ "${1}" = all ] 36 | then 37 | rm -rf template.dmg template.dmg.bz2 wc/ wc.dmg 38 | fi 39 | 40 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Encompass - lightweight multi-coin client 2 | 3 | Encompass consolidates support for various currencies into one wallet. It is a BIP-0044-compliant multi-currency wallet based on Electrum. This Encompass client uses Electrum servers of supported currencies to retrieve necessary data, so no "Encompass server" is necessary. 4 | 5 | Licence: GNU GPL v3 6 | Author: Tyler Willis 7 | Contributors: Thomas Voegtlin (Electrum author), mazaclub, pooler, and many more 8 | Language: Python 9 | Homepage: https://maza.club/encompass 10 | 11 | 1. Please see the appropriate README for your OS installation 12 | - README-OSX.md 13 | - README-Windows.md 14 | - README-Ubuntu.md 15 | - README-source.md 16 | 17 | 18 | 19 | 2. HOW OFFICIAL PACKAGES ARE CREATED 20 | ------------------------------------ 21 | 22 | See contrib/encompass-release/README.md for complete details on 23 | mazaclub's release process 24 | 25 | 26 | 3. HOW COIN-SPECIFIC MODULES ARE CREATED 27 | ---------------------------------------- 28 | 29 | See lib/chains/README.md. 30 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/build-binary: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ -z "$1" ]]; then 4 | echo "Please supply version number" 5 | exit 6 | else 7 | VERSION=$1 8 | fi 9 | 10 | function cleanup(){ 11 | # Remove stale wine sockets 12 | rm -rf /tmp/.wine-* 13 | } 14 | 15 | cleanup 16 | 17 | SOURCEDIR=/opt/wine-electrum/drive_c/encompass/Encompass-$VERSION 18 | 19 | 20 | cd $SOURCEDIR 21 | 22 | $PYTHON "C:/PyInstaller/pyinstaller.py" -y "C:/encompass/deterministic.spec" 23 | cp /opt/wine-electrum/drive_c/encompass/encompass.nsi $SOURCEDIR/ 24 | 25 | echo "Running c:/encompass/Encompass-$VERSION/encompass.nsi for install" 26 | xvfb-run wine c:\\"Program Files"\\NSIS\\makensis.exe -V1 c:/encompass/Encompass-$VERSION/encompass.nsi 27 | 28 | 29 | cleanup 30 | test -d /root/release-packages/Windows || mkdir -pv /root/release-packages/Windows 31 | mv /opt/wine-electrum/drive_c/encompass/Encompass-${VERSION}/dist/encompass-setup.exe /root/release-packages/Windows/Encompass-${VERSION}-Windows-setup.exe 32 | mv /opt/wine-electrum/drive_c/encompass/Encompass-${VERSION}/dist/encompass.exe /root/release-packages/Windows/Encompass-${VERSION}-Windows.exe 33 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/build_osx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -xeo pipefail 3 | VERSION="${1}" 4 | test -z ${VERSION} && exit 1 5 | 6 | if [ "$(uname)" = "Darwin" ]; 7 | then 8 | 9 | if [ ! -f /opt/local/bin/python2.7 ] 10 | then 11 | echo "This build requires macports python2.7 and pyqt4" 12 | exit 5 13 | fi 14 | VER="$1" 15 | sed 's/ELECTRUM_VERSION/'${VER}'/g' Makefile.in > Makefile 16 | cd repo 17 | /opt/local/bin/python2.7 setup-release.py py2app 18 | test -d ../src || mkdir ../src 19 | mv dist/Encompass.app ../src/ 20 | cd .. 21 | #make - makes the unneeded dmg 22 | test -d helpers/release-packages/OSX || mkdir -pv helpers/release-packages/OSX 23 | #mv Encompass-${VER}.dmg helpers/release-packages/OSX 24 | mv src/Encompass.app helpers/release-packages/OSX 25 | cp helpers/make_OSX-installer.sh helpers/release-packages/OSX 26 | thisdir=$(pwd) 27 | cd helpers/release-packages/OSX 28 | ./make_OSX-installer.sh $VERSION 29 | cd ${thisdir} 30 | else 31 | echo "OSX Build Requires OSX build host!" 32 | fi 33 | -------------------------------------------------------------------------------- /icons.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | icons/encompass.png 4 | icons/clock1.png 5 | icons/clock2.png 6 | icons/clock3.png 7 | icons/clock4.png 8 | icons/clock5.png 9 | icons/confirmed.png 10 | icons/key.png 11 | icons/lock.png 12 | icons/unlock.png 13 | icons/preferences.png 14 | icons/seed.png 15 | icons/hot_seed.png 16 | icons/cold_seed.png 17 | icons/status_connected.png 18 | icons/status_disconnected.png 19 | icons/status_waiting.png 20 | icons/status_lagging.png 21 | icons/switchgui.png 22 | icons/electrum_light_icon.png 23 | icons/electrum_dark_icon.png 24 | icons/unconfirmed.png 25 | icons/network.png 26 | icons/dark_background.png 27 | icons/qrcode.png 28 | icons/trustedcoin.png 29 | 30 | 31 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/setup.py-darkcoin_hash-1.1: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | import os 3 | del os.link 4 | 5 | darkcoin_hash_module = Extension('darkcoin_hash', 6 | sources = ['darkcoinmodule.c', 7 | 'darkcoin.c', 8 | 'sha3/blake.c', 9 | 'sha3/bmw.c', 10 | 'sha3/groestl.c', 11 | 'sha3/jh.c', 12 | 'sha3/keccak.c', 13 | 'sha3/skein.c', 14 | 'sha3/cubehash.c', 15 | 'sha3/echo.c', 16 | 'sha3/luffa.c', 17 | 'sha3/simd.c', 18 | 'sha3/shavite.c'], 19 | include_dirs=['.', './sha3']) 20 | 21 | setup (name = 'darkcoin_hash', 22 | version = '1.1', 23 | description = 'Bindings for proof of work used by Darkcoin', 24 | ext_modules = [darkcoin_hash_module]) 25 | -------------------------------------------------------------------------------- /scripts/peers: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import util, json 4 | from collections import defaultdict 5 | 6 | 7 | def analyze(results): 8 | out = {} 9 | dd = {} 10 | for k, v in results.items(): 11 | height = v.get('block_height') 12 | merkle = v.get('merkle_root') 13 | utxo = v.get('utxo_root') 14 | d = dd.get(merkle, defaultdict(int)) 15 | d[utxo] += 1 16 | dd[merkle] = d 17 | refs = {} 18 | for merkle, d in dd.items(): 19 | v = d.values() 20 | m = max(v) 21 | ref = d.keys()[v.index(m)] 22 | refs[merkle] = ref, m 23 | for k, v in results.items(): 24 | height = v.get('block_height') 25 | merkle = v.get('merkle_root') 26 | utxo = v.get('utxo_root') 27 | ref_utxo, num = refs.get(merkle) 28 | if ref_utxo != utxo and num > 1: 29 | out[k] = height, merkle, utxo 30 | return out 31 | 32 | 33 | peers = util.get_peers() 34 | results = util.send_request(peers, {'method':'blockchain.headers.subscribe','params':[]}) 35 | 36 | errors = analyze(results).keys() 37 | 38 | for n,v in sorted(results.items(), key=lambda x:x[1]['block_height']): 39 | print "%40s"%n, v['block_height'], v['utxo_root'], "error" if n in errors else "ok" 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /README-Linux-x86_64.md: -------------------------------------------------------------------------------- 1 | Encompass - lightweight multi-coin client 2 | 3 | Encompass consolidates support for various currencies into one wallet. It is a BIP-0044-compliant multi-currency wallet based on Electrum. This Encompass client uses Electrum servers of supported currencies to retrieve necessary data, so no "Encompass server" is necessary. 4 | 5 | Homepage: https://maza.club/encompass 6 | 7 | 1. ENCOMPASS ON LINUX 8 | ---------------------- 9 | 10 | - Installer package is provided at https://maza.club/encompass 11 | - To download and use: 12 | ``` 13 | cd ~ 14 | wget https://github.com/mazaclub/encompass/releases/v0.5.0/Encompass-0.5.0-Linux_x86_64.tgz 15 | tar -xpzvf Encompass-0.5.0-Linux_x86_64.tgz 16 | cd Encompass-0.5.0 17 | ./encompass_x86_64.bin 18 | ``` 19 | 20 | 21 | Once successfully installed simply type 22 | ``` 23 | encompass 24 | ``` 25 | Your wallets will be located in /home/YOUR_LOGIN_NAME/.encompass/wallets 26 | 27 | Installation on 32bit machines is best achieved via github master or TAGGED branches 28 | 29 | 2. HOW OFFICIAL PACKAGES ARE CREATED 30 | ------------------------------------ 31 | 32 | See contrib/encompass-release/README.md for complete details on mazaclub release process 33 | 34 | 3. HOW COIN-SPECIFIC MODULES ARE CREATED 35 | ---------------------------------------- 36 | 37 | See lib/chains/README.md. 38 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/wip/build_osx-pyinstaller.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -xeo pipefail 3 | VERSION="${1}" 4 | test -z ${VERSION} && exit 1 5 | 6 | if [ "$(uname)" = "Darwin" ]; 7 | then 8 | 9 | if [ ! -f /opt/local/bin/python2.7 ] 10 | then 11 | echo "This build requires macports python2.7 and pyqt4" 12 | exit 5 13 | fi 14 | VER="$1" 15 | sed 's/ELECTRUM_VERSION/'${VER}'/g' Makefile.in > Makefile 16 | sed 's/ELECTRUM_VERSION/'${VER}'/g' cp ../source/osx.spec > repo/osx.spec 17 | cd repo 18 | #/opt/local/bin/python2.7 setup-release.py py2app 19 | pyinstaller --windowed osx.spec 20 | test -d ../src || mkdir ../src 21 | mv dist/Encompass.app ../src/ 22 | cd .. 23 | #make - makes the unneeded dmg 24 | test -d helpers/release-packages/OSX || mkdir -pv helpers/release-packages/OSX 25 | #mv Encompass-${VER}.dmg helpers/release-packages/OSX 26 | mv src/Encompass.app helpers/release-packages/OSX 27 | cp helpers/make_OSX-installer.sh helpers/release-packages/OSX 28 | cp helpers/fix_OSX-pyinstaller.sh helpers/release-packages/OSX 29 | thisdir=$(pwd) 30 | cd helpers/release-packages/OSX 31 | ./fix_OSX-pyinstaller.sh 32 | ./make_OSX-installer.sh $VERSION 33 | cd ${thisdir} 34 | else 35 | echo "OSX Build Requires OSX build host!" 36 | fi 37 | -------------------------------------------------------------------------------- /data/cleanlook/style.css: -------------------------------------------------------------------------------- 1 | #main_window 2 | { 3 | background: qlineargradient(x1: 0, y1: 0, x2:0,y2:1, stop: 0 white , stop: 1 #E8E8E8); 4 | } 5 | 6 | MiniWindow QPushButton { 7 | color: #777; 8 | border: 1px solid #CCC; 9 | border-radius: 0px; 10 | background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 11 | stop: 0 white, stop: 1 #E6E6E6); 12 | min-height: 30px; 13 | min-width: 30px; 14 | } 15 | 16 | #send_button{ 17 | color: #FFF; 18 | border: 1px solid #3786E6; 19 | border-radius: 4px; 20 | background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 21 | stop: 0 #72B2F8, stop: 1 #3484E6); 22 | padding: 2px; 23 | width: 20px; 24 | } 25 | 26 | #send_button:disabled{ 27 | color: #D3E8FE; 28 | border: 1px solid #6DAEF7; 29 | border-radius: 4px; 30 | background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 31 | stop: 0 #A5CFFA, stop: 1 #72B2F8); 32 | } 33 | #address_input, #amount_input, #label_input 34 | { 35 | color: #000; 36 | padding: 5px; 37 | border-radius: 5px; 38 | min-height: 23px; 39 | border: 1px solid #AAA9A9; 40 | width: 200px; 41 | } 42 | 43 | #address_input[isValid=true] 44 | { 45 | color: #4D9948; 46 | } 47 | 48 | #address_input[isValid=false] 49 | { 50 | color: #CE4141; 51 | } 52 | 53 | #balance_label 54 | { 55 | color: #333; 56 | } 57 | 58 | #history 59 | { 60 | color: #888; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /scripts/merchant/merchant.readme: -------------------------------------------------------------------------------- 1 | merchant.py is a daemon that manages payments for a web server. It 2 | creates Bitcoin addresses using a master public key (so you do not 3 | leave your private keys on the server), detects when payments are 4 | received and notifies your web application. 5 | 6 | The workflow goes like this: 7 | 8 | - the server sends a request to the daemon via POST. the request 9 | contains an amount to be paid, a number of confirmations, and an 10 | expiration period in hours. 11 | 12 | - the daemon answers with a Bitcoin address, where the customer needs 13 | to send the coins. 14 | 15 | - later, the daemon will send a POST to the webserver, to notify that 16 | the payment has been received OR that the request has expired 17 | 18 | 19 | Since addresses are generated using an Electrum master public key, it 20 | is possible to visualize payments in the Electrum client; you will, 21 | however, need to manually adjust your "gap limit". 22 | 23 | In order to use this script, first edit and rename 24 | merchant.conf.template to merchant.conf 25 | 26 | to launch it, type: 27 | > python merchant.py 28 | 29 | In another terminal, you may send a request from the command line (it 30 | will send the request to the running daemon via http). For example, 31 | here is a request for 0.1 bitcoins, that requires two confirmations, 32 | and expires in 120 minutes: 33 | 34 | > python merchant.py request 0.1 2 120 35 | 36 | 37 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/make_android: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | if __name__ == '__main__': 5 | import sys, re, shutil, os, hashlib 6 | import imp 7 | os.chdir(os.path.dirname(os.path.realpath(__file__))) 8 | 9 | imp.load_module('electrum', *imp.find_module('lib')) 10 | from electrum.version import ELECTRUM_VERSION as version 11 | 12 | if not ( os.path.exists('packages')): 13 | print "The packages directory is missing." 14 | sys.exit() 15 | 16 | 17 | os.system('rm -rf dist/e4a-%s'%version) 18 | os.mkdir('dist/e4a-%s'%version) 19 | shutil.copyfile("encompass",'dist/e4a-%s/e4a.py'%version) 20 | shutil.copytree("packages",'dist/e4a-%s/packages'%version) 21 | shutil.copytree("lib",'dist/e4a-%s/lib'%version) 22 | os.mkdir('dist/e4a-%s/gui'%version) 23 | for n in ['android.py']: 24 | shutil.copy("gui/%s"%n,'dist/e4a-%s/gui'%version) 25 | open('dist/e4a-%s/gui/__init__.py'%version,'w').close() 26 | 27 | os.chdir("dist") 28 | # create the zip file 29 | os.system( "zip -r e4a-%s.zip e4a-%s"%(version, version) ) 30 | os.system( "rm -rf e4a-%s"%(version) ) 31 | 32 | # change filename because some 3G carriers do not allow users to download a zip file... 33 | e4a_name = "e4a-%s.zip"%version 34 | e4a_name2 = e4a_name.replace(".","") 35 | os.system( "mv %s %s"%(e4a_name, e4a_name2) ) 36 | print "dist/%s "%e4a_name2 37 | 38 | 39 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/make_packages: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys, re, shutil, os, hashlib 4 | import imp 5 | import getpass 6 | 7 | if __name__ == '__main__': 8 | 9 | os.chdir(os.path.dirname(os.path.realpath(__file__))) 10 | #os.chdir('..') 11 | 12 | imp.load_module('electrum', *imp.find_module('lib')) 13 | from electrum.version import ELECTRUM_VERSION as version 14 | 15 | if not ( os.path.exists('packages')): 16 | print "The packages directory is missing." 17 | sys.exit() 18 | 19 | # os.system("python mki18n.py") 20 | os.system("pyrcc4 icons.qrc -o gui/qt/icons_rc.py") 21 | os.system("python setup.py sdist --format=zip,gztar") 22 | 23 | _tgz="Encompass-%s.tar.gz"%version 24 | _zip="Encompass-%s.zip"%version 25 | 26 | os.chdir("dist") 27 | #password = getpass.getpass("Password:") 28 | for f in [_tgz,_zip]: 29 | os.system( "echo SUMS" ) 30 | #gpg --sign --armor --detach --passphrase \"%s\" %s"%(password, f) ) 31 | 32 | md5_tgz = hashlib.md5(file(_tgz, 'r').read()).digest().encode('hex') 33 | md5_zip = hashlib.md5(file(_zip, 'r').read()).digest().encode('hex') 34 | os.chdir("..") 35 | 36 | print "" 37 | print "Packages are ready:" 38 | print "dist/%s "%_tgz, md5_tgz 39 | print "dist/%s "%_zip, md5_zip 40 | print "To make a release, upload the files to the server, and update the webpages in branch gh-pages" 41 | 42 | -------------------------------------------------------------------------------- /lib/qrscanner.py: -------------------------------------------------------------------------------- 1 | import os 2 | from i18n import _ 3 | 4 | try: 5 | import zbar 6 | except ImportError: 7 | zbar = None 8 | 9 | proc = None 10 | 11 | 12 | def scan_qr(config): 13 | global proc 14 | if not zbar: 15 | raise BaseException("\n".join([_("Cannot start QR scanner."),_("The zbar package is not available."),_("On Linux, try 'sudo apt-get install python-zbar'")])) 16 | if proc is None: 17 | device = config.get("video_device", "default") 18 | if device == 'default': 19 | device = '' 20 | proc = zbar.Processor() 21 | proc.init(video_device=device) 22 | 23 | proc.visible = True 24 | while True: 25 | try: 26 | proc.process_one() 27 | except Exception: 28 | # User closed the preview window 29 | return "" 30 | for r in proc.results: 31 | if str(r.type) != 'QRCODE': 32 | continue 33 | # hiding the preview window stops the camera 34 | proc.visible = False 35 | return r.data 36 | 37 | def _find_system_cameras(): 38 | device_root = "/sys/class/video4linux" 39 | devices = {} # Name -> device 40 | if os.path.exists(device_root): 41 | for device in os.listdir(device_root): 42 | name = open(os.path.join(device_root, device, 'name')).read() 43 | name = name.strip('\n') 44 | devices[name] = os.path.join("/dev",device) 45 | return devices 46 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/make_windows: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys, re, shutil, os, hashlib 4 | import imp 5 | import getpass 6 | 7 | if __name__ == '__main__': 8 | 9 | os.chdir(os.path.dirname(os.path.realpath(__file__))) 10 | #os.chdir('..') 11 | 12 | imp.load_module('electrum', *imp.find_module('lib')) 13 | from electrum.version import ELECTRUM_VERSION as version 14 | 15 | if not ( os.path.exists('packages')): 16 | print "The packages directory is missing." 17 | sys.exit() 18 | 19 | # os.system("python mki18n.py") 20 | os.system("pyrcc4 icons.qrc -o gui/qt/icons_rc.py") 21 | shutil.copytree("packages",'dist/Encompass-%s/packages'%version) 22 | os.system("python setup.py sdist --format=zip,gztar") 23 | 24 | _tgz="Encompass-%s.tar.gz"%version 25 | _zip="Encompass-%s.zip"%version 26 | 27 | os.chdir("dist") 28 | #password = getpass.getpass("Password:") 29 | for f in [_tgz,_zip]: 30 | os.system( "echo SUMS" ) 31 | #os.system( "gpg --sign --armor --detach --passphrase \"%s\" %s"%(password, f) ) 32 | 33 | md5_tgz = hashlib.md5(file(_tgz, 'r').read()).digest().encode('hex') 34 | md5_zip = hashlib.md5(file(_zip, 'r').read()).digest().encode('hex') 35 | os.chdir("..") 36 | 37 | print "" 38 | print "Packages are ready:" 39 | print "dist/%s "%_tgz, md5_tgz 40 | print "dist/%s "%_zip, md5_zip 41 | print "To make a release, upload the files to the server, and update the webpages in branch gh-pages" 42 | 43 | -------------------------------------------------------------------------------- /README-ArchLinux.md: -------------------------------------------------------------------------------- 1 | Encompass - lightweight multi-coin client 2 | 3 | Encompass consolidates support for various currencies into one wallet. It is a BIP-0044-compliant multi-currency wallet based on Electrum. This Encompass client uses Electrum servers of supported currencies to retrieve necessary data, so no "Encompass server" is necessary. 4 | 5 | Licence: GNU GPL v3 6 | Author: Tyler Willis 7 | Contributors: Thomas Voegtlin (Electrum author), mazaclub, pooler, and many more 8 | Language: Python 9 | Homepage: https://maza.club/encompass 10 | 11 | 1. ENCOMPASS ON ARCHLINUX 12 | ---------------------- 13 | 14 | * Official Arch Maintainer: Qhor Vertoe 15 | * Official Encompass Arch repo: https://aur.archlinux.org/packages/en/encompass-git/encompass-git.tar.gz 16 | - contrib/ArchLinux contains the most recent contents from the above link ** as of build time ** 17 | - ** contrib/ArchLinux may not reflect post-build changes, version updates. ** 18 | - you are encouraged to use the official repo, contents are mirrored here for verification 19 | ``` 20 | wget https://aur.archlinux.org/packages/en/encompass-git/encompass-git.tar.gz \ 21 | && tar -xpzvf encompass-git.tar.gz \ 22 | && cd encompass-git \ 23 | && mkpkg -s \ 24 | && sudo pacman -U encompass-git-$VERSION.pkg.tar.xz 25 | ``` 26 | 27 | 2. HOW OFFICIAL PACKAGES ARE CREATED 28 | ------------------------------------ 29 | 30 | See contrib/encompass-release/README.md for complete details on mazaclub release process 31 | 32 | 3. HOW COIN-SPECIFIC MODULES ARE CREATED 33 | ---------------------------------------- 34 | 35 | See lib/chains/README.md. 36 | -------------------------------------------------------------------------------- /README-OSX.md: -------------------------------------------------------------------------------- 1 | ### Encompass - lightweight multi-coin client 2 | 3 | Encompass consolidates support for various currencies into one wallet. It is a BIP-0044-compliant multi-currency wallet based on Electrum. This Encompass client uses Electrum servers of supported currencies to retrieve necessary data, so no "Encompass server" is necessary. 4 | 5 | Homepage: https://maza.club/encompass 6 | ## Encompass on OSX 7 | 8 | 1. Download the .dmg from https://maza.club/encompass 9 | 2. Open .dmg in Finder 10 | 3. Double Click Encompass.pkg 11 | 4. Follow instructions to install Encompass 12 | 13 | Encompass will be installed by default to /Applications 14 | 15 | Your Wallets will be stored in /Users/YOUR_LOGIN_NAME/.encompass/wallets 16 | 17 | ### KNOWN ISSUES 18 | 1. Certain dialog boxes fail to open in the foreground 19 | ** Click the Encompass Icon in the Dock to bring correct window to top ** 20 | 21 | 22 | 23 | 2. HOW OFFICIAL PACKAGES ARE CREATED 24 | ------------------------------------ 25 | 26 | contrib/encompass-release 27 | 28 | 29 | The 'build' script will perform all the necessary tasks to 30 | create a release from release-tagged github sources 31 | 32 | If all runs correctly, you''ll find a release set in the 33 | contrib/encompass-release/releases directory, complete with 34 | md5/sha1 sums, and gpg signatures for all files. 35 | 36 | Additional documentation is provided in the README in that dir. 37 | Official Releases are created with a single OSX machine, boot2docker vm and docker 38 | 39 | 40 | 41 | 42 | 3. HOW COIN-SPECIFIC MODULES ARE CREATED 43 | ---------------------------------------- 44 | 45 | See lib/chains/README.md. 46 | -------------------------------------------------------------------------------- /lib/tests/test_chains_base58.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from lib import bitcoin 3 | from lib import chainparams 4 | 5 | class ChainsBase58Test(unittest.TestCase): 6 | 7 | def setUp(self): 8 | super(ChainsBase58Test, self).setUp() 9 | chainparams.set_active_chain('BTC') 10 | 11 | class TestChainsBase58(ChainsBase58Test): 12 | 13 | def setUp(self): 14 | super(TestChainsBase58, self).setUp() 15 | self.masterkey = 'xprv9s21ZrQH143K2AyWpResEyFfXb4J8BDDjUfG9WH7Q199E91HvHnPMM33yxLBFMcDe61QKRZvAiVLWLhxnRQg9pvGPvK7Acca3V9CZ21KSY9' 16 | self.privkey = bitcoin.deserialize_xkey(self.masterkey)[4] 17 | 18 | def test_wif_encoding(self): 19 | active_chain = chainparams.get_active_chain() 20 | wif = bitcoin.SecretToASecret(self.privkey, compressed=True, addrtype = active_chain.wif_version) 21 | self.assertEqual('L3PoHZXjsvP91C8WuyiwzYKgjzthZD2Q39Wzrwfsndov6Cwcu8zX', wif) 22 | 23 | addr = bitcoin.address_from_private_key(wif, addrtype = active_chain.p2pkh_version, wif_version = active_chain.wif_version) 24 | self.assertEqual('1599aBMAHbgEkf4dzvd9jxBFgVyufZVVc1', addr) 25 | 26 | chainparams.set_active_chain('MZC') 27 | active_chain = chainparams.get_active_chain() 28 | wif = bitcoin.SecretToASecret(self.privkey, compressed=True, addrtype = active_chain.wif_version) 29 | self.assertEqual('aF4LB486ggLLYsQG1FcgRFQSdiBKhP4BfZKWaYvxvaAF7z6MGkAG', wif) 30 | 31 | addr = bitcoin.address_from_private_key(wif, addrtype = active_chain.p2pkh_version, wif_version = active_chain.wif_version) 32 | self.assertEqual('MC3JocFZncr3eL2yDuH5zDnb9is5GUzUJv', addr) 33 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/90-trezor.rules: -------------------------------------------------------------------------------- 1 | # This is a sample udev file for HIDAPI devices which changes the permissions 2 | # to 0666 (world readable/writable) for a specified device on Linux systems. 3 | 4 | 5 | # If you are using the libusb implementation of hidapi (hid-libusb.c), then 6 | # use something like the following line, substituting the VID and PID with 7 | # those of your device. Note that for kernels before 2.6.24, you will need 8 | # to substitute "usb" with "usb_device". It shouldn't hurt to use two lines 9 | # (one each way) for compatibility with older systems. 10 | 11 | # HIDAPI/libusb 12 | SUBSYSTEM=="usb", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", MODE="0666" 13 | 14 | 15 | # If you are using the hidraw implementation, then do something like the 16 | # following, substituting the VID and PID with your device. Busnum 1 is USB. 17 | 18 | # HIDAPI/hidraw 19 | KERNEL=="hidraw*", ATTRS{busnum}=="1", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", MODE="0666" 20 | 21 | # Once done, optionally rename this file for your device, and drop it into 22 | # /etc/udev/rules.d and unplug and re-plug your device. This is all that is 23 | # necessary to see the new permissions. Udev does not have to be restarted. 24 | 25 | # Note that the hexadecimal values for VID and PID are case sensitive and 26 | # must be lower case. 27 | 28 | # If you think permissions of 0666 are too loose, then see: 29 | # http://reactivated.net/writing_udev_rules.html for more information on finer 30 | # grained permission setting. For example, it might be sufficient to just 31 | # set the group or user owner for specific devices (for example the plugdev 32 | # group on some systems). 33 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ### How To Contribute to Encompass 2 | 3 | The general workflow process is centered around git-flow & github Pull Requests 4 | 5 | 1. Fork mazaclub/encompass to your own repo 6 | 2. Clone to your local work environment 7 | 3. cd into the newly created repo 8 | 4. Init gitflow 9 | 5. Use gitflow to start a feature 10 | 6. complete feature 11 | 7. Push feature to your github repo 12 | 7. On github create a Pull Request from your feature branch to mazaclub/encompass:develop 13 | 8. Please comment on your PR the reason/need for your feature, and provide an example of real-world testing/usage 14 | 15 | In general, features should be accompanied by appropriate unit tests. 16 | If your PR is a simple PR it will likely be accepted and merged quickly - if it is more complex, 17 | you are encouraged to join us in #mazaclub to discuss. 18 | 19 | # General Development 20 | 21 | Use of gitflow recommended, but not required. 22 | All new features should be based off develop branch, not master 23 | Feature PRs should be submitted to develop, not master 24 | 25 | # Releases 26 | Releases are made with gitflow, release branches are made from develop approximately every 2weeks 27 | Release branches are merged into master and tagged. 28 | 29 | # Bugfixes 30 | 31 | With a rapid release cycle, most bugfixes are treated as features, and integrated into the following release. 32 | Non-crucial bugfixes should be integrated as *features* in the next release cycle - please follow feature workflow 33 | 34 | Crucial bugfixes are based on master, and primarily developed by committers. 35 | 36 | If you have a bugfix that should or must be merged before the next release cycle: 37 | - Demonstrate reproducibility 38 | - Base crucial bugfixes on master 39 | - Submit PR from your bugfix branch via github to mazaclub/encompass:master 40 | 41 | 42 | -------------------------------------------------------------------------------- /lib/i18n.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Electrum - lightweight Bitcoin client 4 | # Copyright (C) 2012 thomasv@gitorious 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import gettext, os 20 | 21 | if os.path.exists('./locale'): 22 | LOCALE_DIR = './locale' 23 | else: 24 | LOCALE_DIR = '/usr/share/locale' 25 | 26 | language = gettext.translation('electrum', LOCALE_DIR, fallback = True) 27 | 28 | 29 | def _(x): 30 | global language 31 | return language.ugettext(x) 32 | 33 | def set_language(x): 34 | global language 35 | if x: language = gettext.translation('electrum', LOCALE_DIR, fallback = True, languages=[x]) 36 | 37 | 38 | languages = { 39 | '':_('Default'), 40 | 'pt_PT':_('Portuguese'), 41 | 'pt_BR':_('Brasilian'), 42 | 'cs_CZ':_('Czech'), 43 | 'de_DE':_('German'), 44 | 'eo_UY':_('Esperanto'), 45 | 'en_UK':_('English'), 46 | 'es_ES':_('Spanish'), 47 | 'fr_FR':_('French'), 48 | 'it_IT':_('Italian'), 49 | 'ja_JP':_('Japanese'), 50 | 'lv_LV':_('Latvian'), 51 | 'nl_NL':_('Dutch'), 52 | 'ru_RU':_('Russian'), 53 | 'sl_SI':_('Slovenian'), 54 | 'ta_IN':_('Tamil'), 55 | 'vi_VN':_('Vietnamese'), 56 | 'zh_CN':_('Chinese') 57 | } 58 | -------------------------------------------------------------------------------- /contrib/make_download: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import sys 3 | import hashlib 4 | import os 5 | 6 | from versions import version, version_win, version_mac, template_path, dl_path 7 | 8 | with open(template_path) as f: 9 | string = f.read() 10 | 11 | _tgz = "Encompass-%s.tar.gz" % version 12 | _zip = "Encompass-%s.zip" % version 13 | 14 | _mac = "encompass-%s.dmg" % version_mac 15 | _win = "encompass-%s.exe" % version_win 16 | _win_setup = "encompass-%s-setup.exe" % version_win 17 | _win_portable = "encompass-%s-portable.exe" % version_win 18 | 19 | md5_tgz = hashlib.md5(file('dist/'+_tgz, 'r').read()).digest().encode('hex') 20 | md5_zip = hashlib.md5(file('dist/'+_zip, 'r').read()).digest().encode('hex') 21 | 22 | for n in [_win, _win_portable, _win_setup, _mac]: 23 | if not os.path.exists("binaries/%s" % n): 24 | # No website as of writing 25 | #os.system("wget http://download.electrum.org/download/%s -O binaries/%s" % (n, n)) 26 | 27 | md5_mac = hashlib.md5(file('binaries/'+_mac, 'r').read()).digest().encode('hex') 28 | md5_win = hashlib.md5(file('binaries/'+_win, 'r').read()).digest().encode('hex') 29 | md5_win_setup = hashlib.md5(file('binaries/'+_win_setup, 'r').read()).digest().encode('hex') 30 | md5_win_portable = hashlib.md5(file('binaries/'+_win_portable, 'r').read()).digest().encode('hex') 31 | 32 | string = string.replace("##VERSION##", version) 33 | string = string.replace("##VERSION_WIN##", version_win) 34 | string = string.replace("##VERSION_MAC##", version_mac) 35 | string = string.replace("##md5_tgz##", md5_tgz) 36 | string = string.replace("##md5_zip##", md5_zip) 37 | string = string.replace("##md5_mac##", md5_mac) 38 | string = string.replace("##md5_win##", md5_win) 39 | string = string.replace("##md5_win_setup##", md5_win_setup) 40 | string = string.replace("##md5_win_portable##", md5_win_portable) 41 | 42 | with open(dl_path,'w') as f: 43 | f.write(string) 44 | 45 | -------------------------------------------------------------------------------- /contrib/ArchLinux/encompass-git/.SRCINFO: -------------------------------------------------------------------------------- 1 | # Generated by makepkg 4.2.1 2 | # Mon Apr 13 19:11:17 UTC 2015 3 | pkgbase = encompass-git 4 | pkgdesc = Multi-currency wallet based on Electrum. Supports Bitcoin, Litecoin, Dash, Mazacoin, Viacoin (git development version). 5 | pkgver = 4216.3b91b31 6 | pkgrel = 1 7 | url = https://github.com/mazaclub/encompass 8 | install = encompass.install 9 | arch = any 10 | license = GPL3 11 | makedepends = gettext 12 | makedepends = git 13 | makedepends = protobuf 14 | makedepends = python2-pycurl 15 | makedepends = python2-setuptools 16 | makedepends = python2-pip 17 | depends = hicolor-icon-theme 18 | depends = python2 19 | depends = python2-ecdsa 20 | depends = python2-pbkdf2 21 | depends = python2-protobuf 22 | depends = python2-pyasn1 23 | depends = python2-pyasn1-modules 24 | depends = python2-pyqt4 25 | depends = python2-qrcode 26 | depends = python2-requests 27 | depends = python2-six 28 | depends = python2-slowaes 29 | depends = python2-tlslite 30 | depends = python2-socksipy-branch 31 | depends = qt4 32 | optdepends = desktop-file-utils: update desktop icon 33 | optdepends = gtk-update-icon-cache: update desktop icon 34 | optdepends = python2-amodem: air-gapped transaction signing over audio modem 35 | optdepends = python2-btchip: BTChip hardware wallet support 36 | optdepends = python2-dnspython: OpenAlias plugin 37 | optdepends = python2-jsonrpclib: merchant script 38 | optdepends = python2-matplotlib: plot transaction history in graphical mode 39 | optdepends = python2-rpyc: send commands to Encompass Python console from an external script 40 | optdepends = python2-trezor: TREZOR hardware wallet support 41 | optdepends = xdg-utils: update desktop icon 42 | optdepends = zbar: QR code reading support 43 | provides = encompass 44 | conflicts = encompass 45 | source = git+https://github.com/mazaclub/encompass 46 | sha256sums = SKIP 47 | 48 | pkgname = encompass-git 49 | 50 | -------------------------------------------------------------------------------- /RELEASE-NOTES: -------------------------------------------------------------------------------- 1 | # Release 0.5.0 2 | 3 | * Produce Linux,OSX,Windows binary releases 4 | * Implement Trezor Hardware wallet 5 | - trezor wallets are supported on all chains 6 | - custom firmware is required to access chains not supported in official firmware form Trezor 7 | * Implement Multisignature wallets 8 | - Primary multisig wallet type in Encompass is based on an as-yet draft BIP 9 | - Encompass-multisig supports a single root key to derive addresses on all chains 10 | * Chain-specific WIF version bytes now used 11 | * Installation & Build Enhancements 12 | - build system is updated to include building OSX and Linux binary release packages 13 | - setup.py and setup-release.py modified to support user installation, sandbox building/installs 14 | * Bug-Fixes 15 | - o not include next_account address in wallet.addresses() 16 | - via - disable diff calc (use not implemented) 17 | * Update icons 18 | 19 | # Release 0.4.4 20 | 21 | * Fixes issues with password encryption of seed & master privkeys 22 | - previous versions would only correctly update the encryption of the active chain 23 | - this could result in seed and/or master privkeys being unencrypted 24 | - this version will correct old wallets, however users are advised to move funds if leaking deleted data is a concern 25 | - more details available on https://maza.club/encompass 26 | 27 | * Implements updated Change Currency dialog, now shows status of PoW checks being done in ChainKey module, and 28 | number of servers listed in the module. 29 | 30 | * Makes Windows releases more deterministic - specifies all dependencies in make_packages, resolves issues with requests module 31 | 32 | # Release 0.4.0 33 | 34 | * Implement Darkcoin Chainkey module 35 | 36 | * Add chain-specfic uri handling, dust, fees, coinbase maturity constants 37 | 38 | * add additional default servers 39 | 40 | * Update Encompass logo icons 41 | 42 | * correct setup.py to correctly compile & include ltc_scrypt 43 | 44 | # Release 0.3.0 45 | 46 | * Implement VIAcoin ChainKey module 47 | 48 | * MZC reorg handler improved 49 | 50 | * URI support added 51 | 52 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/make_linux: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -xeo pipefail 3 | 4 | VERSION="${1}" 5 | test -z ${VERSION} && exit 1 6 | 7 | test -d /root/encompass-release/helpers/release-packages/Linux \ 8 | && rm -rf /root/encompass-release/helpers/release-packages/Linux 9 | cd /root/repo 10 | rm -rf build dist packages 11 | test -f /root/linux_installer.sh && rm /root/linux_installer.sh 12 | find ./ -name '*.pyc' | xargs rm 13 | mkdir packages 14 | pip install --upgrade --target packages -r ../requirements.txt 15 | cp /root/encompass-release/python-trezor/trezorctl packages/trezorctl.py 16 | cp -av /root/packages/google/__init__.py /root/repo/packages/google 17 | cp /root/encompass-release/source/linux.spec /root/repo 18 | su build -c 'pyinstaller --windowed linux.spec' 19 | cd dist 20 | #mv encompass Encompass-"${VERSION}" 21 | #put installer script in here 22 | mkdir /root/encompass-release/helpers/release-packages/Linux 23 | sed -e 's/ELECTRUM_VERSION/'${VERSION}'/g' /root/linux_installer.in > /tmp/linux_installer.sh 24 | cp /tmp/linux_installer.sh /root 25 | chmod 755 /root/linux_installer.sh 26 | mkdir Encompass-${VERSION} 27 | mv encompass Encompass-${VERSION} 28 | cp /root/repo/icons/encompass.png Encompass-${VERSION} 29 | cp /root/repo/README-Linux-x86_64.md Encompass-${VERSION} 30 | cp /root/repo/LICENSE Encompass-${VERSION} 31 | cp /root/repo/RELEASE-NOTES Encompass-${VERSION} 32 | cp /root/repo/AUTHORS Encompass-${VERSION} 33 | cp /root/90-trezor.rules Encompass-${VERSION} 34 | cp /root/encompass_linux_startup.sh Encompass-${VERSION}/encompass.sh 35 | cp /root/repo/encompass.desktop Encompass-${VERSION} 36 | sed -e '/tail/d' /root/linux_installer.sh > Encompass-${VERSION}/linux_installer.sh 37 | tar -cpzvf Encompass-"${VERSION}"_Linux_x86_64.tgz Encompass-"${VERSION}" 38 | cat /root/linux_installer.sh Encompass-"${VERSION}"_Linux_x86_64.tgz > /root/encompass-release/helpers/release-packages/Linux/Encompass-"${VERSION}"_Linux_x86_64-Installer.bin 39 | chmod 555 /root/encompass-release/helpers/release-packages/Linux/Encompass-"${VERSION}"_Linux_x86_64-Installer.bin 40 | 41 | #mv Encompass-"${VERSION}"_Linux-x86_64.tgz /root/encompass-release/helpers/release-packages/Linux 42 | 43 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/make_OSX-installer.sh: -------------------------------------------------------------------------------- 1 | VERSION="${1}" 2 | test -z ${VERSION} && exit 1 3 | PRODUCT_NAME=Encompass 4 | 5 | set -xeo pipefail 6 | BUILD_REPO=../../../repo 7 | BUILT_PRODUCTS_DIR=./ 8 | INSTALL_ROOT=${PRODUCT_NAME}.app 9 | PACKAGE_NAME=`echo "$PRODUCT_NAME" | sed "s/ /_/g"` 10 | TMP1_ARCHIVE="${BUILT_PRODUCTS_DIR}/$PACKAGE_NAME-tmp1.pkg" 11 | TMP2_ARCHIVE="${BUILT_PRODUCTS_DIR}/$PACKAGE_NAME-tmp2" 12 | TMP3_ARCHIVE="${BUILT_PRODUCTS_DIR}/$PACKAGE_NAME-tmp3.pkg" 13 | ARCHIVE_FILENAME="${BUILT_PRODUCTS_DIR}/${PACKAGE_NAME}.pkg" 14 | 15 | test -d Resources/en.lproj || mkdir -pv Resources/en.lproj 16 | cp -av ${BUILD_REPO}/README-OSX.md Resources/en.lproj/Readme 17 | cp -av ${BUILD_REPO}/LICENSE Resources/en.lproj/License 18 | cp -av ${BUILD_REPO}/icons/encompass-logo.jpg Resources/en.lproj/background 19 | 20 | 21 | 22 | #pkgbuild --analyze --root ${INSTALL_ROOT} 'Encompass.plist' 23 | 24 | #--component-plist "./${PRODUCT_NAME}.plist" \ 25 | pkgbuild --root "${INSTALL_ROOT}" \ 26 | --version "$VERSION" \ 27 | --identifier "org.pythonmac.unspecified.${PRODUCT_NAME}" \ 28 | --install-location "/Applications/${PRODUCT_NAME}.app" \ 29 | "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}-pre.pkg" 30 | 31 | productbuild --synthesize \ 32 | --package ${PRODUCT_NAME}-pre.pkg \ 33 | Distribution.in 34 | cat Distribution.in 35 | 36 | #echo "sed" 37 | sed -e '$ i\ 38 | \ Encompass '${VERSION}'' \ 39 | -e '$ i\ 40 | \ ' \ 41 | -e '$ i\ 42 | \ ' \ 43 | -e '$ i\ 44 | \ ' \ 45 | -e '$ i\ 46 | \ ' \ 47 | -e '$ i\ 48 | \ ' Distribution.in > Distribution.xml 49 | 50 | productbuild --distribution "./Distribution.xml" \ 51 | --package-path "${BUILT_PRODUCTS_DIR}" \ 52 | --resources "./Resources" \ 53 | "${TMP1_ARCHIVE}" 54 | 55 | # Unnecessary placeholders 56 | pkgutil --expand "${TMP1_ARCHIVE}" "${TMP2_ARCHIVE}" 57 | 58 | # Patches and Workarounds 59 | 60 | pkgutil --flatten "${TMP2_ARCHIVE}" "${TMP3_ARCHIVE}" 61 | cp ${TMP3_ARCHIVE} ${PRODUCT_NAME}-Installer.pkg 62 | 63 | -------------------------------------------------------------------------------- /mki18n.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | from StringIO import StringIO 3 | import urllib2, os, zipfile, pycurl 4 | 5 | crowdin_identifier = 'electrum' 6 | crowdin_file_name = 'electrum-client/messages.pot' 7 | locale_file_name = 'locale/messages.pot' 8 | 9 | if os.path.exists('contrib/crowdin_api_key.txt'): 10 | crowdin_api_key = open('contrib/crowdin_api_key.txt').read() 11 | 12 | # Generate fresh translation template 13 | if not os.path.exists('locale'): 14 | os.mkdir('locale') 15 | 16 | cmd = 'xgettext -s --no-wrap -f app.fil --output=locale/messages.pot' 17 | print 'Generate template' 18 | os.system(cmd) 19 | 20 | # Push to Crowdin 21 | print 'Push to Crowdin' 22 | url = ('http://api.crowdin.net/api/project/' + crowdin_identifier + '/update-file?key=' + crowdin_api_key) 23 | 24 | c = pycurl.Curl() 25 | c.setopt(c.URL, url) 26 | c.setopt(c.POST, 1) 27 | fields = [('files[' + crowdin_file_name + ']', (pycurl.FORM_FILE, locale_file_name))] 28 | c.setopt(c.HTTPPOST, fields) 29 | c.perform() 30 | 31 | # Build translations 32 | print 'Build translations' 33 | response = urllib2.urlopen('http://api.crowdin.net/api/project/' + crowdin_identifier + '/export?key=' + crowdin_api_key).read() 34 | print response 35 | 36 | # Download & unzip 37 | print 'Download translations' 38 | zfobj = zipfile.ZipFile(StringIO(urllib2.urlopen('http://crowdin.net/download/project/' + crowdin_identifier + '.zip').read())) 39 | 40 | print 'Unzip translations' 41 | for name in zfobj.namelist(): 42 | if not name.startswith('electrum-client/locale'): 43 | continue 44 | if name.endswith('/'): 45 | if not os.path.exists(name[16:]): 46 | os.mkdir(name[16:]) 47 | else: 48 | output = open(name[16:],'w') 49 | output.write(zfobj.read(name)) 50 | output.close() 51 | 52 | # Convert .po to .mo 53 | print 'Installing' 54 | for lang in os.listdir('./locale'): 55 | if lang.startswith('messages'): 56 | continue 57 | # Check LC_MESSAGES folder 58 | mo_dir = 'locale/%s/LC_MESSAGES' % lang 59 | if not os.path.exists(mo_dir): 60 | os.mkdir(mo_dir) 61 | cmd = 'msgfmt --output-file="%s/electrum.mo" "locale/%s/electrum.po"' % (mo_dir,lang) 62 | print 'Installing',lang 63 | os.system(cmd) 64 | -------------------------------------------------------------------------------- /scripts/util.py: -------------------------------------------------------------------------------- 1 | import time, electrum, Queue 2 | from chainkey import Interface, SimpleConfig 3 | from chainkey.network import filter_protocol, parse_servers 4 | 5 | # electrum.util.set_verbosity(1) 6 | 7 | def get_peers(): 8 | # 1. start interface and wait for connection 9 | interface = electrum.Interface('ecdsa.net:110:s') 10 | q = Queue.Queue() 11 | interface.start(q) 12 | i, r = q.get() 13 | if not interface.is_connected: 14 | raise BaseException("not connected") 15 | # 2. get list of peers 16 | interface.send_request({'id':0, 'method':'server.peers.subscribe','params':[]}) 17 | i, r = q.get(timeout=10000) 18 | peers = parse_servers(r.get('result')) 19 | peers = filter_protocol(peers,'s') 20 | i.stop() 21 | return peers 22 | 23 | def send_request(peers, request): 24 | print "Contacting %d servers"%len(peers) 25 | # start interfaces 26 | q2 = Queue.Queue() 27 | config = SimpleConfig() 28 | interfaces = map ( lambda server: Interface(server, config), peers ) 29 | reached_servers = [] 30 | for i in interfaces: 31 | i.start(q2) 32 | t0 = time.time() 33 | while peers: 34 | try: 35 | i, r = q2.get(timeout=1) 36 | except: 37 | if time.time() - t0 > 10: 38 | print "timeout" 39 | break 40 | else: 41 | continue 42 | if i.server in peers: 43 | peers.remove(i.server) 44 | if i.is_connected: 45 | reached_servers.append(i) 46 | else: 47 | print "Connection failed:", i.server 48 | 49 | print "%d servers could be reached"%len(reached_servers) 50 | 51 | results_queue = Queue.Queue() 52 | for i in reached_servers: 53 | i.send_request(request, results_queue) 54 | results = {} 55 | t0 = time.time() 56 | while reached_servers: 57 | try: 58 | i, r = results_queue.get(timeout=1) 59 | except: 60 | if time.time() - t0 > 10: 61 | break 62 | else: 63 | continue 64 | results[i.server] = r.get('result') 65 | reached_servers.remove(i) 66 | i.stop() 67 | 68 | for i in reached_servers: 69 | print i.server, "did not answer" 70 | print "%d answers"%len(results) 71 | return results 72 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/make_locale: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | from StringIO import StringIO 3 | import urllib2, os, zipfile, pycurl 4 | 5 | os.chdir(os.path.dirname(os.path.realpath(__file__))) 6 | os.chdir('..') 7 | 8 | # Generate fresh translation template 9 | if not os.path.exists('lib/locale'): 10 | os.mkdir('lib/locale') 11 | cmd = 'xgettext -s --no-wrap -f app.fil --output=lib/locale/messages.pot' 12 | print 'Generate template' 13 | os.system(cmd) 14 | 15 | os.chdir('lib') 16 | 17 | crowdin_identifier = 'encompass' 18 | crowdin_file_name = 'encompass-client/messages.pot' 19 | locale_file_name = 'locale/messages.pot' 20 | 21 | if os.path.exists('../contrib/crowdin_api_key.txt'): 22 | crowdin_api_key = open('../contrib/crowdin_api_key.txt').read().strip() 23 | # Push to Crowdin 24 | print 'Push to Crowdin' 25 | url = ('http://api.crowdin.net/api/project/' + crowdin_identifier + '/update-file?key=' + crowdin_api_key) 26 | c = pycurl.Curl() 27 | c.setopt(c.URL, url) 28 | c.setopt(c.POST, 1) 29 | fields = [('files[' + crowdin_file_name + ']', (pycurl.FORM_FILE, locale_file_name))] 30 | c.setopt(c.HTTPPOST, fields) 31 | c.perform() 32 | # Build translations 33 | print 'Build translations' 34 | response = urllib2.urlopen('http://api.crowdin.net/api/project/' + crowdin_identifier + '/export?key=' + crowdin_api_key).read() 35 | print response 36 | 37 | # Download & unzip 38 | print 'Download translations' 39 | zfobj = zipfile.ZipFile(StringIO(urllib2.urlopen('http://crowdin.net/download/project/' + crowdin_identifier + '.zip').read())) 40 | 41 | print 'Unzip translations' 42 | for name in zfobj.namelist(): 43 | if not name.startswith('encompass-client/locale'): 44 | continue 45 | if name.endswith('/'): 46 | if not os.path.exists(name[16:]): 47 | os.mkdir(name[16:]) 48 | else: 49 | output = open(name[16:],'w') 50 | output.write(zfobj.read(name)) 51 | output.close() 52 | 53 | # Convert .po to .mo 54 | print 'Installing' 55 | for lang in os.listdir('locale'): 56 | if lang.startswith('messages'): 57 | continue 58 | # Check LC_MESSAGES folder 59 | mo_dir = 'locale/%s/LC_MESSAGES' % lang 60 | if not os.path.exists(mo_dir): 61 | os.mkdir(mo_dir) 62 | cmd = 'msgfmt --output-file="%s/encompass.mo" "locale/%s/encompass.po"' % (mo_dir,lang) 63 | print 'Installing',lang 64 | os.system(cmd) 65 | -------------------------------------------------------------------------------- /plugins/virtualkeyboard.py: -------------------------------------------------------------------------------- 1 | from PyQt4.QtGui import * 2 | from chainkey.plugins import BasePlugin, hook 3 | from chainkey.i18n import _ 4 | 5 | class Plugin(BasePlugin): 6 | 7 | 8 | def fullname(self): 9 | return 'Virtual Keyboard' 10 | 11 | def description(self): 12 | return '%s\n%s' % (_("Add an optional virtual keyboard to the password dialog."), _("Warning: do not use this if it makes you pick a weaker password.")) 13 | 14 | def is_available(self): 15 | return True 16 | # Disabled until compatibility is ensured 17 | return False 18 | 19 | @hook 20 | def init_qt(self, gui): 21 | self.gui = gui 22 | self.vkb = None 23 | self.vkb_index = 0 24 | 25 | @hook 26 | def password_dialog(self, pw, grid, pos): 27 | vkb_button = QPushButton(_("+")) 28 | vkb_button.setFixedWidth(20) 29 | vkb_button.clicked.connect(lambda: self.toggle_vkb(grid, pw)) 30 | grid.addWidget(vkb_button, pos, 2) 31 | self.kb_pos = 2 32 | 33 | 34 | def toggle_vkb(self, grid, pw): 35 | if self.vkb: grid.removeItem(self.vkb) 36 | self.vkb = self.virtual_keyboard(self.vkb_index, pw) 37 | grid.addLayout(self.vkb, self.kb_pos, 0, 1, 3) 38 | self.vkb_index += 1 39 | 40 | 41 | def virtual_keyboard(self, i, pw): 42 | import random 43 | i = i%3 44 | if i == 0: 45 | chars = 'abcdefghijklmnopqrstuvwxyz ' 46 | elif i == 1: 47 | chars = 'ABCDEFGHIJKLMNOPQRTSUVWXYZ ' 48 | elif i == 2: 49 | chars = '1234567890!?.,;:/%&()[]{}+-' 50 | 51 | n = len(chars) 52 | s = [] 53 | for i in xrange(n): 54 | while True: 55 | k = random.randint(0,n-1) 56 | if k not in s: 57 | s.append(k) 58 | break 59 | 60 | def add_target(t): 61 | return lambda: pw.setText(str( pw.text() ) + t) 62 | 63 | vbox = QVBoxLayout() 64 | grid = QGridLayout() 65 | grid.setSpacing(2) 66 | for i in range(n): 67 | l_button = QPushButton(chars[s[i]]) 68 | l_button.setFixedWidth(25) 69 | l_button.setFixedHeight(25) 70 | l_button.clicked.connect(add_target(chars[s[i]]) ) 71 | grid.addWidget(l_button, i/6, i%6) 72 | 73 | vbox.addLayout(grid) 74 | 75 | return vbox 76 | 77 | -------------------------------------------------------------------------------- /data/sahara/style.css: -------------------------------------------------------------------------------- 1 | #main_window 2 | { 3 | background: qlineargradient(x1: 0, y1: 0, x2:0,y2:1, stop: 0 white , stop: 1 #F2E3BE); 4 | } 5 | 6 | MiniWindow QPushButton { 7 | color: #C1A76D; 8 | border: 1px solid #A7811C; 9 | border-radius: 0px; 10 | background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 11 | stop: 0 white, stop: 1 #F2E3BE); 12 | min-height: 25px; 13 | min-width: 30px; 14 | } 15 | 16 | #send_button{ 17 | color: #FEEBA7; 18 | border: 1px solid #AD8B35; 19 | border-radius: 4px; 20 | background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 21 | stop: 0 #E0A035, stop: 1 #AD8B35); 22 | min-width: 80px; 23 | min-height: 23px; 24 | padding: 2px; 25 | } 26 | 27 | #send_button:disabled{ 28 | color: #FEEDD3; 29 | border: 1px solid #F7D46D; 30 | border-radius: 4px; 31 | background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 32 | stop: 0 #FAEEA5, stop: 1 #DBC050); 33 | min-width: 80px; 34 | min-height: 23px; 35 | padding: 2px; 36 | } 37 | 38 | #receive_button 39 | { 40 | color: #FEEBA7; 41 | border: 1px solid #AD8B35; 42 | border-radius: 4px; 43 | background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 44 | stop: 0 #E0A035, stop: 1 #AD8B35); 45 | min-height: 25px; 46 | min-width: 30px; 47 | } 48 | #receive_button[isActive=true] 49 | { 50 | color: #FEEBA7; 51 | background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 52 | stop: 0 #E0A035, stop: 1 #987620); 53 | } 54 | 55 | #address_input, #amount_input 56 | { 57 | color: #000; 58 | padding: 5px; 59 | border-radius: 4px; 60 | border: 1px solid #CBAE69; 61 | width: 225px; 62 | } 63 | 64 | #address_input[isValid=true] 65 | { 66 | color: #4D9948; 67 | padding: 5px; 68 | border-radius: 4px; 69 | border: 1px solid #CBAE69; 70 | width: 225px; 71 | margin-top: 4px; 72 | } 73 | 74 | #address_input[isValid=false] 75 | { 76 | color: #CE4141; 77 | padding: 5px; 78 | border-radius: 4px; 79 | border: 1px solid #CBAE69; 80 | width: 225px; 81 | margin-top: 4px; 82 | } 83 | 84 | #address_input[isValid=placeholder] 85 | { 86 | color: #DEC58D; 87 | padding: 5px; 88 | border-radius: 4px; 89 | border: 1px solid #CBAE69; 90 | width: 225px; 91 | margin-top: 4px; 92 | } 93 | #balance_label 94 | { 95 | color: #7E5907; 96 | } 97 | 98 | #history 99 | { 100 | color: #8B6914; 101 | } 102 | 103 | -------------------------------------------------------------------------------- /lib/paymentrequest.proto: -------------------------------------------------------------------------------- 1 | // 2 | // Simple Bitcoin Payment Protocol messages 3 | // 4 | // Use fields 1000+ for extensions; 5 | // to avoid conflicts, register extensions via pull-req at 6 | // https://github.com/bitcoin/bips/bip-0070/extensions.mediawiki 7 | // 8 | 9 | package payments; 10 | option java_package = "org.bitcoin.protocols.payments"; 11 | option java_outer_classname = "Protos"; 12 | 13 | // Generalized form of "send payment to this/these bitcoin addresses" 14 | message Output { 15 | optional uint64 amount = 1 [default = 0]; // amount is integer-number-of-satoshis 16 | required bytes script = 2; // usually one of the standard Script forms 17 | } 18 | message PaymentDetails { 19 | optional string network = 1 [default = "main"]; // "main" or "test" 20 | repeated Output outputs = 2; // Where payment should be sent 21 | required uint64 time = 3; // Timestamp; when payment request created 22 | optional uint64 expires = 4; // Timestamp; when this request should be considered invalid 23 | optional string memo = 5; // Human-readable description of request for the customer 24 | optional string payment_url = 6; // URL to send Payment and get PaymentACK 25 | optional bytes merchant_data = 7; // Arbitrary data to include in the Payment message 26 | } 27 | message PaymentRequest { 28 | optional uint32 payment_details_version = 1 [default = 1]; 29 | optional string pki_type = 2 [default = "none"]; // none / x509+sha256 / x509+sha1 30 | optional bytes pki_data = 3; // depends on pki_type 31 | required bytes serialized_payment_details = 4; // PaymentDetails 32 | optional bytes signature = 5; // pki-dependent signature 33 | } 34 | message X509Certificates { 35 | repeated bytes certificate = 1; // DER-encoded X.509 certificate chain 36 | } 37 | message Payment { 38 | optional bytes merchant_data = 1; // From PaymentDetails.merchant_data 39 | repeated bytes transactions = 2; // Signed transactions that satisfy PaymentDetails.outputs 40 | repeated Output refund_to = 3; // Where to send refunds, if a refund is necessary 41 | optional string memo = 4; // Human-readable message for the merchant 42 | } 43 | message PaymentACK { 44 | required Payment payment = 1; // Payment message that triggered this ACK 45 | optional string memo = 2; // human-readable message for customer 46 | } 47 | -------------------------------------------------------------------------------- /contrib/encompass-release/source/deterministic.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | 3 | # We don't put these files in to actually include them in the script but to make the Analysis method scan them for imports 4 | a = Analysis(['encompass', 'gui/qt/main_window.py', 'gui/qt/lite_window.py', 'gui/text.py', 5 | 'lib/util.py', 'lib/wallet.py', 'lib/simple_config.py', 6 | 'lib/bitcoin.py','lib/interface.py','packages/trezorctl.py' 7 | ], 8 | hiddenimports=["lib","gui","plugins","hid"], 9 | pathex=['lib','gui','plugins','packages','packages/requests'], 10 | hookspath=None) 11 | 12 | ##### include mydir in distribution ####### 13 | def extra_datas(mydir): 14 | def rec_glob(p, files): 15 | import os 16 | import glob 17 | for d in glob.glob(p): 18 | if os.path.isfile(d): 19 | files.append(d) 20 | rec_glob("%s/*" % d, files) 21 | files = [] 22 | rec_glob("%s/*" % mydir, files) 23 | extra_datas = [] 24 | for f in files: 25 | extra_datas.append((f, f, 'DATA')) 26 | 27 | return extra_datas 28 | ########################################### 29 | 30 | # append dirs 31 | 32 | # Theme data 33 | a.datas += extra_datas('data') 34 | 35 | # Localization 36 | a.datas += extra_datas('locale') 37 | 38 | # Py folders that are needed because of the magic import finding 39 | a.datas += extra_datas('gui') 40 | a.datas += extra_datas('lib') 41 | a.datas += extra_datas('plugins') 42 | #a.datas += [ ('packages/requests/cacert.pem', 'packages/requests/cacert.pem', 'DATA') ] 43 | 44 | # Dependencies 45 | a.datas += extra_datas('packages') 46 | 47 | pyz = PYZ(a.pure) 48 | exe = EXE(pyz, 49 | a.scripts, 50 | a.binaries, 51 | a.datas, 52 | name=os.path.join('build\\pyi.win32\\encompass', 'encompass.exe'), 53 | debug=False, 54 | strip=None, 55 | upx=False, 56 | icon='icons/encompass.ico', 57 | console=False) 58 | # The console True makes an annoying black box pop up, but it does make encompass output command line commands, with this turned off no output will be given but commands can still be used 59 | 60 | coll = COLLECT(exe, 61 | a.binaries, 62 | a.zipfiles, 63 | a.datas, 64 | strip=None, 65 | upx=True, 66 | debug=False, 67 | icon='icons/encompass.ico', 68 | console=False, 69 | name=os.path.join('dist', 'encompass')) 70 | -------------------------------------------------------------------------------- /contrib/encompass-release/Makefile.in: -------------------------------------------------------------------------------- 1 | # 2 | # Build file for creating DMG files. 3 | # 4 | # The DMG packager looks for a template.dmg.bz2 for using as its 5 | # DMG template. If it doesn't find one, it generates a clean one. 6 | # 7 | # If you create a DMG template, you should make one containing all 8 | # the files listed in $(SOURCE_FILES) below, and arrange everything to suit 9 | # your style. The contents of the files themselves does not matter, so 10 | # they can be empty (they will be overwritten later). 11 | # 12 | # Remko Tronçon 13 | # https://el-tramo.be 14 | # Licensed under the MIT License. See COPYING for details. 15 | 16 | 17 | ################################################################################ 18 | # Customizable variables 19 | ################################################################################ 20 | 21 | NAME ?= Encompass 22 | VERSION ?= ELECTRUM_VERSION 23 | 24 | SOURCE_DIR ?= src 25 | SOURCE_FILES ?= Encompass.app 26 | 27 | TEMPLATE_DMG ?= template.dmg 28 | 29 | 30 | ################################################################################ 31 | # DMG building. No editing should be needed beyond this point. 32 | ################################################################################ 33 | 34 | MASTER_DMG=$(NAME)-$(VERSION).dmg 35 | WC_DMG=wc.dmg 36 | WC_DIR=wc 37 | 38 | .PHONY: all 39 | all: $(MASTER_DMG) 40 | 41 | $(TEMPLATE_DMG): $(TEMPLATE_DMG).bz2 42 | bunzip2 -k $< 43 | 44 | $(TEMPLATE_DMG).bz2: 45 | @echo 46 | @echo --------------------- Generating empty template -------------------- 47 | mkdir template 48 | hdiutil create -fs HFSX -layout SPUD -size 100m "$(TEMPLATE_DMG)" -srcfolder template -format UDRW -volname "$(NAME)" -quiet 49 | rmdir template 50 | bzip2 "$(TEMPLATE_DMG)" 51 | @echo 52 | 53 | $(WC_DMG): $(TEMPLATE_DMG) 54 | cp $< $@ 55 | 56 | $(MASTER_DMG): $(WC_DMG) $(addprefix $(SOURCE_DIR)/,$(SOURCE_FILES)) 57 | @echo 58 | @echo --------------------- Creating Disk Image -------------------- 59 | mkdir -p $(WC_DIR) 60 | hdiutil attach "$(WC_DMG)" -noautoopen -quiet -mountpoint "$(WC_DIR)" 61 | for i in $(SOURCE_FILES); do \ 62 | rm -rf "$(WC_DIR)/$$i"; \ 63 | ditto -rsrc "$(SOURCE_DIR)/$$i" "$(WC_DIR)/$$i"; \ 64 | done 65 | #rm -f "$@" 66 | #hdiutil create -srcfolder "$(WC_DIR)" -format UDZO -imagekey zlib-level=9 "$@" -volname "$(NAME) $(VERSION)" -scrub -quiet 67 | WC_DEV=`hdiutil info | grep "$(WC_DIR)" | grep "Apple_HFS" | awk '{print $$1}'` && \ 68 | hdiutil detach $$WC_DEV -quiet -force 69 | rm -f "$(MASTER_DMG)" 70 | hdiutil convert "$(WC_DMG)" -quiet -format UDZO -imagekey zlib-level=9 -o "$@" 71 | rm -rf $(WC_DIR) 72 | @echo 73 | 74 | .PHONY: clean 75 | clean: 76 | -rm -rf $(TEMPLATE_DMG) $(MASTER_DMG) $(WC_DMG) 77 | -------------------------------------------------------------------------------- /gui/qt/qrtextedit.py: -------------------------------------------------------------------------------- 1 | from chainkey.i18n import _ 2 | from PyQt4.QtGui import * 3 | from PyQt4.QtCore import * 4 | 5 | class QRTextEdit(QPlainTextEdit): 6 | """Abstract class for QR-code related TextEdits. Do not use directly.""" 7 | def __init__(self, text=None): 8 | super(QRTextEdit, self).__init__(text) 9 | self.button = QToolButton(self) 10 | self.button.setIcon(QIcon(":icons/qrcode.png")) 11 | self.button.setStyleSheet("QToolButton { border: none; padding: 0px; }") 12 | self.button.setVisible(True) 13 | self.setText = self.setPlainText 14 | 15 | def resizeEvent(self, e): 16 | o = QPlainTextEdit.resizeEvent(self, e) 17 | sz = self.button.sizeHint() 18 | frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) 19 | self.button.move(self.rect().right() - frameWidth - sz.width(), 20 | (self.rect().bottom() - frameWidth - sz.height())) 21 | return o 22 | 23 | class ShowQRTextEdit(QRTextEdit): 24 | def __init__(self, text=None): 25 | super(ShowQRTextEdit, self).__init__(text) 26 | self.setReadOnly(1) 27 | self.button.clicked.connect(self.qr_show) 28 | 29 | def qr_show(self): 30 | from qrcodewidget import QRDialog 31 | try: 32 | s = str(self.toPlainText()) 33 | except: 34 | s = unicode(self.toPlainText()) 35 | QRDialog(s).exec_() 36 | 37 | def contextMenuEvent(self, e): 38 | m = self.createStandardContextMenu() 39 | m.addAction(_("Show as QR code"), self.qr_show) 40 | m.exec_(e.globalPos()) 41 | 42 | 43 | class ScanQRTextEdit(QRTextEdit): 44 | def __init__(self, win, text=""): 45 | super(ScanQRTextEdit,self).__init__(text) 46 | self.setReadOnly(0) 47 | self.win = win 48 | assert win, "You must pass a window with access to the config to ScanQRTextEdit constructor." 49 | if win: 50 | assert hasattr(win,"config"), "You must pass a window with access to the config to ScanQRTextEdit constructor." 51 | self.button.clicked.connect(self.qr_input) 52 | 53 | 54 | def qr_input(self): 55 | from chainkey import qrscanner 56 | try: 57 | data = qrscanner.scan_qr(self.win.config) 58 | except BaseException, e: 59 | QMessageBox.warning(self, _('Error'), _(e), _('OK')) 60 | return "" 61 | if type(data) != str: 62 | return 63 | self.setText(data) 64 | return data 65 | 66 | def contextMenuEvent(self, e): 67 | m = self.createStandardContextMenu() 68 | m.addAction(_("Read QR code"), self.qr_input) 69 | m.exec_(e.globalPos()) 70 | -------------------------------------------------------------------------------- /contrib/encompass-release/source/linux.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | 3 | # We don't put these files in to actually include them in the script but to make the Analysis method scan them for imports 4 | a = Analysis(['encompass', 'gui/qt/main_window.py', 'gui/qt/lite_window.py', 'gui/text.py', 5 | 'lib/util.py', 'lib/wallet.py', 'lib/simple_config.py','gui/gtk.py', 6 | 'lib/bitcoin.py','lib/interface.py', 'packages/trezorctl.py', 7 | ], 8 | hiddenimports=["PyQt4","lib","gui","plugins","trezorlib","hid"], 9 | pathex=['lib','gui','plugins','packages'], 10 | hookspath=None) 11 | 12 | ##### include mydir in distribution ####### 13 | def extra_datas(mydir): 14 | def rec_glob(p, files): 15 | import os 16 | import glob 17 | for d in glob.glob(p): 18 | if os.path.isfile(d): 19 | files.append(d) 20 | rec_glob("%s/*" % d, files) 21 | files = [] 22 | rec_glob("%s/*" % mydir, files) 23 | extra_datas = [] 24 | for f in files: 25 | extra_datas.append((f, f, 'DATA')) 26 | 27 | return extra_datas 28 | ########################################### 29 | 30 | # append dirs 31 | 32 | # Theme data 33 | a.datas += extra_datas('data') 34 | 35 | # Localization 36 | a.datas += extra_datas('locale') 37 | 38 | # Py folders that are needed because of the magic import finding 39 | a.datas += extra_datas('gui') 40 | a.datas += extra_datas('lib') 41 | a.datas += extra_datas('plugins') 42 | a.datas += [ ('packages/requests/cacert.pem', 'packages/requests/cacert.pem', 'DATA') ] 43 | a.datas += [ ('packages/trezorctl.py', 'packages/trezorctl.py', 'DATA') ] 44 | 45 | # Dependencies 46 | a.datas += extra_datas('packages') 47 | 48 | pyz = PYZ(a.pure) 49 | exe = EXE(pyz, 50 | a.scripts, 51 | a.binaries, 52 | a.datas, 53 | name=os.path.join('build/encompass/encompass', 'encompass-x86_64.bin'), 54 | debug=False, 55 | strip=None, 56 | upx=False, 57 | icon='icons/encompass.ico', 58 | console=False) 59 | # The console True makes an annoying black box pop up, but it does make encompass output command line commands, with this turned off no output will be given but commands can still be used 60 | 61 | coll = COLLECT(exe, 62 | a.binaries, 63 | a.zipfiles, 64 | a.datas, 65 | strip=None, 66 | upx=True, 67 | debug=False, 68 | icon='icons/encompass.ico', 69 | console=False, 70 | name=os.path.join('dist', 'encompass')) 71 | -------------------------------------------------------------------------------- /lib/msqr.py: -------------------------------------------------------------------------------- 1 | # from http://eli.thegreenplace.net/2009/03/07/computing-modular-square-roots-in-python/ 2 | 3 | def modular_sqrt(a, p): 4 | """ Find a quadratic residue (mod p) of 'a'. p 5 | must be an odd prime. 6 | 7 | Solve the congruence of the form: 8 | x^2 = a (mod p) 9 | And returns x. Note that p - x is also a root. 10 | 11 | 0 is returned is no square root exists for 12 | these a and p. 13 | 14 | The Tonelli-Shanks algorithm is used (except 15 | for some simple cases in which the solution 16 | is known from an identity). This algorithm 17 | runs in polynomial time (unless the 18 | generalized Riemann hypothesis is false). 19 | """ 20 | # Simple cases 21 | # 22 | if legendre_symbol(a, p) != 1: 23 | return 0 24 | elif a == 0: 25 | return 0 26 | elif p == 2: 27 | return p 28 | elif p % 4 == 3: 29 | return pow(a, (p + 1) / 4, p) 30 | 31 | # Partition p-1 to s * 2^e for an odd s (i.e. 32 | # reduce all the powers of 2 from p-1) 33 | # 34 | s = p - 1 35 | e = 0 36 | while s % 2 == 0: 37 | s /= 2 38 | e += 1 39 | 40 | # Find some 'n' with a legendre symbol n|p = -1. 41 | # Shouldn't take long. 42 | # 43 | n = 2 44 | while legendre_symbol(n, p) != -1: 45 | n += 1 46 | 47 | # Here be dragons! 48 | # Read the paper "Square roots from 1; 24, 51, 49 | # 10 to Dan Shanks" by Ezra Brown for more 50 | # information 51 | # 52 | 53 | # x is a guess of the square root that gets better 54 | # with each iteration. 55 | # b is the "fudge factor" - by how much we're off 56 | # with the guess. The invariant x^2 = ab (mod p) 57 | # is maintained throughout the loop. 58 | # g is used for successive powers of n to update 59 | # both a and b 60 | # r is the exponent - decreases with each update 61 | # 62 | x = pow(a, (s + 1) / 2, p) 63 | b = pow(a, s, p) 64 | g = pow(n, s, p) 65 | r = e 66 | 67 | while True: 68 | t = b 69 | m = 0 70 | for m in xrange(r): 71 | if t == 1: 72 | break 73 | t = pow(t, 2, p) 74 | 75 | if m == 0: 76 | return x 77 | 78 | gs = pow(g, 2 ** (r - m - 1), p) 79 | g = (gs * gs) % p 80 | x = (x * gs) % p 81 | b = (b * g) % p 82 | r = m 83 | 84 | def legendre_symbol(a, p): 85 | """ Compute the Legendre symbol a|p using 86 | Euler's criterion. p is a prime, a is 87 | relatively prime to p (if p divides 88 | a, then a|p = 0) 89 | 90 | Returns 1 if a has a square root modulo 91 | p, -1 otherwise. 92 | """ 93 | ls = pow(a, (p - 1) / 2, p) 94 | return -1 if ls == p - 1 else ls 95 | -------------------------------------------------------------------------------- /docs/cold_storage: -------------------------------------------------------------------------------- 1 | Here is how to sign a transaction with an offline Electrum wallet. 2 | 3 | 1. With your online (seedless) wallet, create the transaction using 'mktx': 4 | 5 | ./encompass -w seedless_wallet mktx 1Cpf9zb5Rm5Z5qmmGezn6ERxFWvwuZ6UCx 0.1 6 | { 7 | "complete": false, 8 | "hex": "01000000015a92850cc5dc7bb7c1a711c1ce0c1658596c085d49c17fce68c641cce0bdd188010000004801ff45fe197f1a7a7779f58690c3100364d7ce596bf47bb52e88e617e22940bf54a8f139194652584b0d357eb95defb8b4911b0a53118b8afecb96aedb1334e772df350901002800ffffffff02b1f0f65d000000001976a9147ea19cc36d846e2ce81762def3cb9299bed0847188ac80969800000000001976a91451e814c0f7637ba9a59bc11628337a2df6559a5088ac00000000" 9 | } 10 | 11 | Encompass returns an unsigned transaction. Note that the serialization 12 | format contains the master public key needed and key derivation, used 13 | by the offline wallet to sign the transaction. 14 | 15 | 16 | 2. Sign the transaction with your offline wallet, using 'signrawtransaction': 17 | 18 | ./encompass -w wallet_with_seed signrawtransaction 01000000015a92850cc5dc7bb7c1a711c1ce0c1658596c085d49c17fce68c641cce0bdd188010000004801ff45fe197f1a7a7779f58690c3100364d7ce596bf47bb52e88e617e22940bf54a8f139194652584b0d357eb95defb8b4911b0a53118b8afecb96aedb1334e772df350901002800ffffffff02b1f0f65d000000001976a9147ea19cc36d846e2ce81762def3cb9299bed0847188ac80969800000000001976a91451e814c0f7637ba9a59bc11628337a2df6559a5088ac00000000 19 | Password: 20 | { 21 | "complete": true, 22 | "hex": "01000000015a92850cc5dc7bb7c1a711c1ce0c1658596c085d49c17fce68c641cce0bdd188010000008b483045022100c65dd8899d4e1d12b1ebaa0ea15835f9a158343733fbe990cdfebde2164d89c802201a5a8fe737b07daf700aeecf3b6a4111c563ebc181da75b1f264883060c273da0141040beb415f075a532982fe982d01736453d4e3413566c79a39d16679474c7ab94022269b9f726edc152a89dfcf18cd3dd2a38fc5e442f24d22a51545ca42beb7b5ffffffff02b1f0f65d000000001976a9147ea19cc36d846e2ce81762def3cb9299bed0847188ac80969800000000001976a91451e814c0f7637ba9a59bc11628337a2df6559a5088ac00000000" 23 | } 24 | 25 | The result is a fully signed transaction, as indicated by the "complete" field. 26 | 27 | 28 | 3. Broadcast the transaction to the Bitcoin network, using 'sendrawtransaction': 29 | 30 | ./electrum sendrawtransaction 01000000015a92850cc5dc7bb7c1a711c1ce0c1658596c085d49c17fce68c641cce0bdd188010000008b483045022100c65dd8899d4e1d12b1ebaa0ea15835f9a158343733fbe990cdfebde2164d89c802201a5a8fe737b07daf700aeecf3b6a4111c563ebc181da75b1f264883060c273da0141040beb415f075a532982fe982d01736453d4e3413566c79a39d16679474c7ab94022269b9f726edc152a89dfcf18cd3dd2a38fc5e442f24d22a51545ca42beb7b5ffffffff02b1f0f65d000000001976a9147ea19cc36d846e2ce81762def3cb9299bed0847188ac80969800000000001976a91451e814c0f7637ba9a59bc11628337a2df6559a5088ac00000000 31 | "ef6b561232f3c507219ab7d2a79f8849e14ed7e926e77546c2d9e751905b825b" 32 | -------------------------------------------------------------------------------- /docs/android.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Encompass for Android

5 | 6 | This page explains how to install Encompass on Android devices.

7 | 8 | Please note that Encompass is not distributed as a binary package, but 9 | as python source code; this gives users the possibility to see what 10 | the code is doing, and to check that it does not contain malware. The 11 | downside is that installation is slightly more complicated than 12 | downloading an app on the Android market, but it remains very 13 | simple.

14 | 15 | It is possible to print this page on paper and to install everything from 16 | QR codes. If you encounter problems, you may find help at 17 | 18 | this link. 19 | 20 | 21 |

1. Download and install Google Scripting Layer for Android

22 | 23 | You can get 24 | it here, 25 | or by scanning the following qr code:
26 | 28 | 29 | 30 |

2. Download and install Python for Android

31 | 32 | You can get 33 | it here, 34 | or by scanning the following qr code:
35 | 36 |
37 | Once you have installed the apk, launch the Python for Android application and click 'install' 38 | 39 |

3. Download the Encompass install script

40 | 41 | Download e4a_install.py and install it in your sl4a/scripts directory. 42 | You can do it manually, or from QR code, as follows: 43 |
44 | 1. Launch SL4A.
45 | 2. Press the Menu button.
46 | 3. Tap Add.
47 | 4. Tap Scan Barcode.
48 | 5. Scan the following QRcode:
49 | 
50 | 52 |
This will install a script named e4a_install.py
53 | 54 |

4. Download and install Encompass

55 |
56 | 1. Tap e4a_install.py: it will download and install a directory named "Encompass-0.43d"
57 | 2. To launch Encompass, visit the "Electrum-0.43d" directory and tap 'encompass4a.py'
58 | 
59 | 60 | 61 | -------------------------------------------------------------------------------- /contrib/encompass-release/source/osx.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | 3 | # We don't put these files in to actually include them in the script but to make the Analysis method scan them for imports 4 | a = Analysis(['encompass', 'gui/qt/main_window.py', 'gui/qt/lite_window.py', 'gui/text.py', 5 | 'lib/util.py', 'lib/wallet.py', 'lib/simple_config.py','gui/gtk.py', 6 | 'lib/bitcoin.py','lib/interface.py', 'packages/trezorctl.py', 7 | ], 8 | hiddenimports=["PyQt4","lib","gui","plugins","trezorlib","hid"], 9 | pathex=['lib','gui','plugins','packages'], 10 | hookspath=None) 11 | 12 | ##### include mydir in distribution ####### 13 | def extra_datas(mydir): 14 | def rec_glob(p, files): 15 | import os 16 | import glob 17 | for d in glob.glob(p): 18 | if os.path.isfile(d): 19 | files.append(d) 20 | rec_glob("%s/*" % d, files) 21 | files = [] 22 | rec_glob("%s/*" % mydir, files) 23 | extra_datas = [] 24 | for f in files: 25 | extra_datas.append((f, f, 'DATA')) 26 | 27 | return extra_datas 28 | ########################################### 29 | 30 | # append dirs 31 | 32 | # Theme data 33 | a.datas += extra_datas('data') 34 | 35 | # Localization 36 | a.datas += extra_datas('locale') 37 | 38 | # Py folders that are needed because of the magic import finding 39 | a.datas += extra_datas('gui') 40 | a.datas += extra_datas('lib') 41 | a.datas += extra_datas('plugins') 42 | a.datas += [ ('packages/requests/cacert.pem', 'packages/requests/cacert.pem', 'DATA') ] 43 | a.datas += [ ('packages/trezorctl.py', 'packages/trezorctl.py', 'DATA') ] 44 | 45 | # Dependencies 46 | a.datas += extra_datas('packages') 47 | 48 | pyz = PYZ(a.pure) 49 | exe = EXE(pyz, 50 | a.scripts, 51 | a.binaries, 52 | a.datas, 53 | name=os.path.join('build/encompass/encompass', 'encompass_osx.bin'), 54 | debug=False, 55 | strip=None, 56 | upx=False, 57 | icon='icons/encompass.ico', 58 | console=False) 59 | # The console True makes an annoying black box pop up, but it does make encompass output command line commands, with this turned off no output will be given but commands can still be used 60 | 61 | coll = COLLECT(exe, 62 | a.binaries, 63 | a.zipfiles, 64 | a.datas, 65 | strip=None, 66 | upx=True, 67 | debug=False, 68 | icon='icons/encompass.ico', 69 | console=False, 70 | name=os.path.join('dist', 'encompass')) 71 | 72 | app = BUNDLE(coll, 73 | name=os.path.join('dist', 'Encompass.app'), 74 | appname="Encompass", 75 | version = 'ELECTRUM_VERSION' 76 | ) 77 | -------------------------------------------------------------------------------- /contrib/encompass-release/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM guruvan/ubuntu-32bit:14.04 2 | # IMAGE 3 | MAINTAINER Rob Nelson 4 | 5 | VOLUME ["/opt/wine-electrum/drive_c/encompass"] 6 | 7 | RUN apt-get update -y \ 8 | && apt-get install -y software-properties-common && add-apt-repository -y ppa:ubuntu-wine/ppa \ 9 | && apt-get update -y \ 10 | && apt-get install -y --no-install-recommends wine1.7 xvfb wget \ 11 | zip \ 12 | winbind \ 13 | && apt-get purge -y python-software-properties \ 14 | && apt-get autoclean -y 15 | RUN apt-get install -y unzip 16 | 17 | # Versions 18 | ENV PYTHON_URL https://www.python.org/ftp/python/2.7.8/python-2.7.8.msi 19 | ENV PYQT4_URL http://downloads.sourceforge.net/project/pyqt/PyQt4/PyQt-4.11.1/PyQt4-4.11.1-gpl-Py2.7-Qt4.8.6-x32.exe?r=http%3A%2F%2Fwww.riverbankcomputing.co.uk%2Fsoftware%2Fpyqt%2Fdownload&ts=1410031650&use_mirror=skylink 20 | ENV PYWIN32_URL http://downloads.sourceforge.net/project/pywin32/pywin32/Build%20217/pywin32-217.win32-py2.7.exe?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fpywin32%2Ffiles%2Fpywin32%2FBuild%2520217%2F&ts=1410031204&use_mirror=kent 21 | ENV PYINSTALLER_URL https://pypi.python.org/packages/source/P/PyInstaller/PyInstaller-2.1.zip 22 | ENV NSIS_URL http://prdownloads.sourceforge.net/nsis/nsis-2.46-setup.exe?download 23 | 24 | # Paths 25 | ENV WINEPREFIX /opt/wine-electrum 26 | RUN export WINEPREFIX=/opt/wine-electrum 27 | 28 | ENV ELECTRUM_PATH $WINE_PREFIX/drive_c/encompass 29 | ENV PYHOME c:/Python27 30 | ENV PYTHON xvfb-run -a wine $PYHOME/python.exe -B 31 | ENV PIP $PYTHON -m pip 32 | 33 | # Only needed for debugging 34 | # RUN apt-get install -y vnc4server 35 | # RUN export DISPLAY=:33 36 | # RUN (echo electrum;echo electrum)|vnc4passwd 37 | # EXPOSE 5933 38 | 39 | 40 | 41 | # Docker kills this run before wine is done setting up, don't remove the sleep 42 | RUN xvfb-run -a --server-num=4 wineboot && sleep 5 \ 43 | && echo 'DIRECTORY IS ' ; pwd \ 44 | && wget -O python.msi "$PYTHON_URL" \ 45 | && xvfb-run -a -e /dev/stdout -a msiexec /q /i python.msi \ 46 | && sleep 5 \ 47 | && wget -O pyinstaller.zip "$PYINSTALLER_URL" && unzip pyinstaller.zip && mv PyInstaller-2.1 $WINEPREFIX/drive_c/pyinstaller \ 48 | && wget -O pywin32.exe "$PYWIN32_URL" \ 49 | && unzip -qq pywin32.exe; echo 'Done pywin' \ 50 | && cp -r PLATLIB/* $WINEPREFIX/drive_c/Python27/Lib/site-packages/ \ 51 | && mkdir -p $WINEPREFIX/drive_c/Python27/Scripts/ \ 52 | && cp -r SCRIPTS/* $WINEPREFIX/drive_c/Python27/Scripts/ \ 53 | && $PYTHON $PYHOME/Scripts/pywin32_postinstall.py -install \ 54 | && wget -O PyQt.exe "$PYQT4_URL" \ 55 | && rm -rf /tmp/.wine-* && xvfb-run -a wine PyQt.exe /S \ 56 | && wget -q -O nsis.exe $NSIS_URL \ 57 | && rm -rf /tmp/.wine-* && xvfb-run -a wine nsis.exe /S 58 | 59 | COPY ./python-trezor/dist/Python27 $WINEPREFIX/drive_c/Python27 60 | # Clean up stale wine processes 61 | RUN rm -rf /tmp/.wine-* 62 | -------------------------------------------------------------------------------- /docs/console.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is the documentation for the Encompass Console.
4 | 5 | 6 |
7 |
8 | Most Encompass command-line commands are also available in the console.
9 | The results are Python objects, even though they are 10 | sometimes rendered as JSON for clarity.
11 |
12 | Let us call listunspent(), to see the list of unspent outputs in the wallet: 13 |
14 | >> listunspent()
15 | [
16 |     {
17 |         "address": "12cmY5RHRgx8KkUKASDcDYRotget9FNso3", 
18 |         "index": 0, 
19 |         "raw_output_script": "76a91411bbdc6e3a27c44644d83f783ca7df3bdc2778e688ac", 
20 |         "tx_hash": "e7029df9ac8735b04e8e957d0ce73987b5c9c5e920ec4a445130cdeca654f096", 
21 |         "value": 0.01
22 |     }, 
23 |     {
24 |         "address": "1GavSCND6TB7HuCnJSTEbHEmCctNGeJwXF", 
25 |         "index": 0, 
26 |         "raw_output_script": "76a914aaf437e25805f288141bfcdc27887ee5492bd13188ac", 
27 |         "tx_hash": "b30edf57ca2a31560b5b6e8dfe567734eb9f7d3259bb334653276efe520735df", 
28 |         "value": 9.04735316
29 |     }
30 | ]
31 | 
32 | Note that the result is rendered as JSON.
33 | However, if we save it to a Python variable, it is rendered as a Python object: 34 |
35 | >> u = listunspent()
36 | >> u
37 | [{'tx_hash': u'e7029df9ac8735b04e8e957d0ce73987b5c9c5e920ec4a445130cdeca654f096', 'index': 0, 'raw_output_script': '76a91411bbdc6e3a27c44644d83f783ca7df3bdc2778e688ac', 'value': 0.01, 'address': '12cmY5RHRgx8KkUKASDcDYRotget9FNso3'}, {'tx_hash': u'b30edf57ca2a31560b5b6e8dfe567734eb9f7d3259bb334653276efe520735df', 'index': 0, 'raw_output_script': '76a914aaf437e25805f288141bfcdc27887ee5492bd13188ac', 'value': 9.04735316, 'address': '1GavSCND6TB7HuCnJSTEbHEmCctNGeJwXF'}]
38 | 
39 |
40 | This makes it possible to combine Electrum commands with Python.
41 | For example, let us pick only the addresses in the previous result: 42 |
43 | >> map(lambda x:x.get('address'), listunspent())
44 | [
45 |     "12cmY5RHRgx8KkUKASDcDYRotget9FNso3", 
46 |     "1GavSCND6TB7HuCnJSTEbHEmCctNGeJwXF"
47 | ]
48 | 
49 | Here we combine two commands, listunspent 50 | and dumpprivkeys, in order to dump the private keys of all adresses that have unspent outputs: 51 |
52 | >> dumpprivkeys( map(lambda x:x.get('address'), listunspent()) )
53 | {
54 |     "12cmY5RHRgx8KkUKASDcDYRotget9FNso3": "***************************************************", 
55 |     "1GavSCND6TB7HuCnJSTEbHEmCctNGeJwXF": "***************************************************"
56 | }
57 | 
58 | Note that dumpprivkey will ask for your password if your 59 | wallet is encrypted. 60 |
61 | The GUI methods can be accessed through the gui variable. 62 | For example, you can display a QR code from a string using 63 | gui.show_qrcode. 64 | Example: 65 |
66 | gui.show_qrcode(dumpprivkey(listunspent()[0]['address']))
67 | 
68 | 69 |
70 | 71 | 72 | -------------------------------------------------------------------------------- /contrib/encompass-release/source/encompass.nsi: -------------------------------------------------------------------------------- 1 | ;-------------------------------- 2 | ;Include Modern UI 3 | 4 | !include "MUI2.nsh" 5 | 6 | ;-------------------------------- 7 | ;General 8 | 9 | ;Name and file 10 | Name "Encompass" 11 | OutFile "dist/encompass-setup.exe" 12 | 13 | ;Default installation folder 14 | InstallDir "$PROGRAMFILES\Encompass" 15 | 16 | ;Get installation folder from registry if available 17 | InstallDirRegKey HKCU "Software\Encompass" "" 18 | 19 | ;Request application privileges for Windows Vista 20 | RequestExecutionLevel admin 21 | 22 | ;-------------------------------- 23 | ;Variables 24 | 25 | ;-------------------------------- 26 | ;Interface Settings 27 | 28 | !define MUI_ABORTWARNING 29 | 30 | ;-------------------------------- 31 | ;Pages 32 | 33 | ;!insertmacro MUI_PAGE_LICENSE "tmp/LICENCE" 34 | ;!insertmacro MUI_PAGE_COMPONENTS 35 | !insertmacro MUI_PAGE_DIRECTORY 36 | 37 | ;Start Menu Folder Page Configuration 38 | !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" 39 | !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\Encompass" 40 | !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" 41 | 42 | ;!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder 43 | 44 | !insertmacro MUI_PAGE_INSTFILES 45 | 46 | !insertmacro MUI_UNPAGE_CONFIRM 47 | !insertmacro MUI_UNPAGE_INSTFILES 48 | 49 | ;-------------------------------- 50 | ;Languages 51 | 52 | !insertmacro MUI_LANGUAGE "English" 53 | 54 | ;-------------------------------- 55 | ;Installer Sections 56 | 57 | Section 58 | 59 | SetOutPath "$INSTDIR" 60 | 61 | ;ADD YOUR OWN FILES HERE... 62 | file /r dist\encompass\*.* 63 | 64 | ;Store installation folder 65 | WriteRegStr HKCU "Software\Encompass" "" $INSTDIR 66 | 67 | ;Create uninstaller 68 | WriteUninstaller "$INSTDIR\Uninstall.exe" 69 | 70 | 71 | CreateShortCut "$DESKTOP\Encompass.lnk" "$INSTDIR\encompass.exe" "" 72 | 73 | ;create start-menu items 74 | CreateDirectory "$SMPROGRAMS\Encompass" 75 | CreateShortCut "$SMPROGRAMS\Encompass\Uninstall.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0 76 | CreateShortCut "$SMPROGRAMS\Encompass\Encompass.lnk" "$INSTDIR\encompass.exe" "" "$INSTDIR\encompass.exe" 0 77 | 78 | SectionEnd 79 | 80 | ;-------------------------------- 81 | ;Descriptions 82 | 83 | ;Assign language strings to sections 84 | ;!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN 85 | ; !insertmacro MUI_DESCRIPTION_TEXT ${SecDummy} $(DESC_SecDummy) 86 | ;!insertmacro MUI_FUNCTION_DESCRIPTION_END 87 | 88 | ;-------------------------------- 89 | ;Uninstaller Section 90 | 91 | Section "Uninstall" 92 | 93 | ;ADD YOUR OWN FILES HERE... 94 | RMDir /r "$INSTDIR\*.*" 95 | 96 | RMDir "$INSTDIR" 97 | 98 | Delete "$DESKTOP\Encompass.lnk" 99 | Delete "$SMPROGRAMS\Encompass\*.*" 100 | RmDir "$SMPROGRAMS\Encompass" 101 | 102 | DeleteRegKey /ifempty HKCU "Software\Encompass" 103 | 104 | SectionEnd 105 | -------------------------------------------------------------------------------- /lib/chains/cryptocur.py: -------------------------------------------------------------------------------- 1 | '''The abstract class for a cryptocurrency.''' 2 | 3 | import os, hashlib 4 | 5 | hash_encode = lambda x: x[::-1].encode('hex') 6 | hash_decode = lambda x: x.decode('hex')[::-1] 7 | 8 | def rev_hex(s): 9 | return s.decode('hex')[::-1].encode('hex') 10 | 11 | def int_to_hex(i, length=1): 12 | s = hex(i)[2:].rstrip('L') 13 | s = "0"*(2*length - len(s)) + s 14 | return rev_hex(s) 15 | 16 | def sha256(x): 17 | return hashlib.sha256(x).digest() 18 | 19 | def Hash(x): 20 | if type(x) is unicode: x=x.encode('utf-8') 21 | return sha256(sha256(x)) 22 | 23 | 24 | 25 | class CryptoCur(object): 26 | '''Abstract class containing cryptocurrency-specific code''' 27 | ### Chain parameters ### 28 | 29 | # Whether this chain verifies Proof-of-Work 30 | PoW = False 31 | 32 | # index used in child key derivation 33 | chain_index = 0 34 | # Full name (e.g. Bitcoin) 35 | coin_name = '' 36 | # Abbreviation (e.g. BTC) 37 | code = '' 38 | # Address base58 prefix 39 | p2pkh_version = 0 40 | # Script hash base58 prefix 41 | p2sh_version = 0 42 | # Private key base58 prefix 43 | wif_version = 0 44 | # Extended pubkey base58 prefix 45 | ext_pub_version = '' 46 | # Extended privkey base58 prefix 47 | ext_priv_version = '' 48 | 49 | ### Constants ### 50 | 51 | DUST_THRESHOLD = 5430 52 | MIN_RELAY_TX_FEE = 1000 53 | RECOMMENDED_FEE = 50000 54 | COINBASE_MATURITY = 100 55 | 56 | 57 | # Block explorers {name : URL} 58 | block_explorers = { 59 | 'Blockchain.info': 'https://blockchain.info/tx/', 60 | 'Blockr.io': 'https://blockr.io/tx/info/', 61 | 'Insight.is': 'http://live.insight.is/tx/', 62 | 'Blocktrail.com': 'https://www.blocktrail.com/tx/' 63 | } 64 | 65 | # Currency units {name : decimal point} 66 | base_units = { 67 | 'COIN': 8, 68 | 'mCOIN': 5 69 | } 70 | 71 | ### Electrum constants ### 72 | 73 | # Number of headers in one chunk 74 | chunk_size = 2016 75 | 76 | ### Methods ### 77 | 78 | 79 | # Tell us where our blockchain_headers file is 80 | def set_headers_path(self, path): 81 | self.headers_path = path 82 | 83 | def path(self): 84 | return self.headers_path 85 | 86 | def verify_chain(self, chain): 87 | pass 88 | 89 | def verify_chunk(self, index, hexdata): 90 | pass 91 | 92 | def header_to_string(self, res): 93 | pass 94 | 95 | def header_from_string(self, s): 96 | pass 97 | 98 | def hash_header(self, header): 99 | pass 100 | 101 | def save_chunk(self, index, chunk): 102 | pass 103 | 104 | def save_header(self, header): 105 | pass 106 | 107 | def read_header(self, block_height): 108 | pass 109 | 110 | # Calculate the difficulty target 111 | def get_target(self, index, chain=None): 112 | pass 113 | 114 | 115 | -------------------------------------------------------------------------------- /gui/qt/qrwindow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Electrum - lightweight Bitcoin client 4 | # Copyright (C) 2014 Thomas Voegtlin 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import re 20 | import platform 21 | from decimal import Decimal 22 | from urllib import quote 23 | 24 | from PyQt4.QtGui import * 25 | from PyQt4.QtCore import * 26 | import PyQt4.QtCore as QtCore 27 | import PyQt4.QtGui as QtGui 28 | 29 | from chainkey_gui.qt.qrcodewidget import QRCodeWidget 30 | from chainkey.i18n import _ 31 | 32 | if platform.system() == 'Windows': 33 | MONOSPACE_FONT = 'Lucida Console' 34 | elif platform.system() == 'Darwin': 35 | MONOSPACE_FONT = 'Monaco' 36 | else: 37 | MONOSPACE_FONT = 'monospace' 38 | 39 | column_index = 4 40 | 41 | class QR_Window(QWidget): 42 | 43 | def __init__(self, win): 44 | QWidget.__init__(self) 45 | self.win = win 46 | self.setWindowTitle('Encompass - '+_('Invoice')) 47 | self.setMinimumSize(800, 250) 48 | self.address = '' 49 | self.label = '' 50 | self.amount = 0 51 | self.setFocusPolicy(QtCore.Qt.NoFocus) 52 | 53 | main_box = QHBoxLayout() 54 | 55 | self.qrw = QRCodeWidget() 56 | main_box.addWidget(self.qrw, 1) 57 | 58 | vbox = QVBoxLayout() 59 | main_box.addLayout(vbox) 60 | 61 | self.address_label = QLabel("") 62 | #self.address_label.setFont(QFont(MONOSPACE_FONT)) 63 | vbox.addWidget(self.address_label) 64 | 65 | self.label_label = QLabel("") 66 | vbox.addWidget(self.label_label) 67 | 68 | self.amount_label = QLabel("") 69 | vbox.addWidget(self.amount_label) 70 | 71 | vbox.addStretch(1) 72 | self.setLayout(main_box) 73 | 74 | 75 | def set_content(self, address, amount, message, url): 76 | address_text = "%s" % address if address else "" 77 | self.address_label.setText(address_text) 78 | if amount: 79 | amount = self.win.format_amount(amount) 80 | amount_text = "%s %s " % (amount, self.win.base_unit()) 81 | else: 82 | amount_text = '' 83 | self.amount_label.setText(amount_text) 84 | label_text = "%s" % message if message else "" 85 | self.label_label.setText(label_text) 86 | self.qrw.setData(url) 87 | -------------------------------------------------------------------------------- /gui/qt/receiving_widget.py: -------------------------------------------------------------------------------- 1 | from PyQt4.QtGui import * 2 | from PyQt4.QtCore import * 3 | from chainkey.i18n import _ 4 | 5 | class ReceivingWidget(QTreeWidget): 6 | 7 | def toggle_used(self): 8 | if self.hide_used: 9 | self.hide_used = False 10 | self.setColumnHidden(2, False) 11 | else: 12 | self.hide_used = True 13 | self.setColumnHidden(2, True) 14 | self.update_list() 15 | 16 | def edit_label(self, item, column): 17 | if column == 1 and item.isSelected(): 18 | self.editing = True 19 | item.setFlags(Qt.ItemIsEditable|Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled) 20 | self.editItem(item, column) 21 | item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled) 22 | self.editing = False 23 | 24 | def update_label(self, item, column): 25 | if self.editing: 26 | return 27 | else: 28 | address = str(item.text(0)) 29 | label = unicode( item.text(1) ) 30 | self.owner.actuator.g.wallet.set_label(address, label) 31 | 32 | def copy_address(self): 33 | address = self.currentItem().text(0) 34 | qApp.clipboard().setText(address) 35 | 36 | 37 | def update_list(self): 38 | return 39 | self.clear() 40 | addresses = self.owner.actuator.g.wallet.addresses(False) 41 | for address in addresses: 42 | history = self.owner.actuator.g.wallet.history.get(address,[]) 43 | 44 | used = "No" 45 | # It appears that at this moment history can either be an array with tx and block height 46 | # Or just a tx that's why this ugly code duplication is in, will fix 47 | if len(history) == 1: 48 | # This means pruned data. If that's the case the address has to been used at one point 49 | if history[0] == "*": 50 | used = "Yes" 51 | else: 52 | for tx_hash in history: 53 | tx = self.owner.actuator.g.wallet.transactions.get(tx_hash) 54 | if tx: 55 | used = "Yes" 56 | else: 57 | for tx_hash, height in history: 58 | tx = self.owner.actuator.g.wallet.transactions.get(tx_hash) 59 | if tx: 60 | used = "Yes" 61 | 62 | if(self.hide_used == True and used == "No") or self.hide_used == False: 63 | label = self.owner.actuator.g.wallet.labels.get(address,'') 64 | item = QTreeWidgetItem([address, label, used]) 65 | self.insertTopLevelItem(0, item) 66 | 67 | def __init__(self, owner=None): 68 | self.owner = owner 69 | self.editing = False 70 | 71 | QTreeWidget.__init__(self, owner) 72 | self.setColumnCount(3) 73 | self.setHeaderLabels([_("Address"), _("Label"), _("Used")]) 74 | self.setIndentation(0) 75 | 76 | self.hide_used = True 77 | self.setColumnHidden(2, True) 78 | -------------------------------------------------------------------------------- /lib/tests/test_chainparams.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from lib import chainparams 3 | 4 | class ChainParamsTestCase(unittest.TestCase): 5 | 6 | def setUp(self): 7 | super(ChainParamsTestCase, self).setUp() 8 | chainparams.set_active_chain('BTC') 9 | 10 | def tearDown(self): 11 | super(ChainParamsTestCase, self).tearDown() 12 | 13 | class TestChainParams(ChainParamsTestCase): 14 | 15 | def test_get_active_chain(self): 16 | chainparams.set_active_chain('MZC') 17 | chain = chainparams.get_active_chain() 18 | self.assertEqual(13, chain.chain_index) 19 | self.assertEqual('Mazacoin', chain.coin_name) 20 | self.assertEqual('MZC', chain.code) 21 | self.assertEqual(50, chain.p2pkh_version) 22 | self.assertEqual(9, chain.p2sh_version) 23 | self.assertEqual(224, chain.wif_version) 24 | 25 | chainparams.set_active_chain('BTC') 26 | chain = chainparams.get_active_chain() 27 | self.assertEqual(0, chain.chain_index) 28 | self.assertEqual('Bitcoin', chain.coin_name) 29 | self.assertEqual('BTC', chain.code) 30 | self.assertEqual(0, chain.p2pkh_version) 31 | self.assertEqual(5, chain.p2sh_version) 32 | self.assertEqual(128, chain.wif_version) 33 | 34 | def test_set_active_chain(self): 35 | chainparams.set_active_chain('MZC') 36 | 37 | def test_is_known_chain(self): 38 | self.assertEqual(True, chainparams.is_known_chain('BTC')) 39 | self.assertEqual(False, chainparams.is_known_chain('FOOBAR')) 40 | 41 | def test_get_params(self): 42 | chainparams.set_active_chain('MZC') 43 | params = chainparams.get_params('MZC') 44 | self.assertEqual(13, params.chain_index) 45 | self.assertEqual('Mazacoin', params.coin_name) 46 | self.assertEqual('MZC', params.code) 47 | self.assertEqual('mazacoin', params.module_name) 48 | 49 | params = chainparams.get_params('BTC') 50 | self.assertEqual(0, params.chain_index) 51 | self.assertEqual('Bitcoin', params.coin_name) 52 | self.assertEqual('BTC', params.code) 53 | self.assertEqual('bitcoin', params.module_name) 54 | 55 | def test_get_chainparam(self): 56 | chainparams.set_active_chain('MZC') 57 | self.assertEqual('Mazacoin', chainparams.get_chainparam('MZC', 'coin_name')) 58 | self.assertEqual('mazacoin', chainparams.get_chainparam('MZC', 'module_name')) 59 | self.assertEqual('Bitcoin', chainparams.get_chainparam('BTC', 'coin_name')) 60 | self.assertEqual('bitcoin', chainparams.get_chainparam('BTC', 'module_name')) 61 | 62 | def test_get_chain_index(self): 63 | chainparams.set_active_chain('MZC') 64 | index = chainparams.get_chain_index('MZC') 65 | self.assertEqual(13, index) 66 | index = chainparams.get_chain_index('BTC') 67 | self.assertEqual(0, index) 68 | 69 | def test_get_code_from_index(self): 70 | chainparams.set_active_chain('MZC') 71 | code = chainparams.get_code_from_index(13) 72 | self.assertEqual('MZC', code) 73 | code = chainparams.get_code_from_index(0) 74 | self.assertEqual('BTC', code) 75 | 76 | -------------------------------------------------------------------------------- /gui/qt/amountedit.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from PyQt4.QtCore import * 4 | from PyQt4.QtGui import * 5 | 6 | from decimal import Decimal 7 | import chainkey.chainparams 8 | 9 | class MyLineEdit(QLineEdit): 10 | frozen = pyqtSignal() 11 | 12 | def setFrozen(self, b): 13 | self.setReadOnly(b) 14 | self.setFrame(not b) 15 | self.frozen.emit() 16 | 17 | class AmountEdit(MyLineEdit): 18 | shortcut = pyqtSignal() 19 | 20 | def __init__(self, base_unit, is_int = False, parent=None): 21 | QLineEdit.__init__(self, parent) 22 | self.base_unit = base_unit 23 | self.textChanged.connect(self.numbify) 24 | self.is_int = is_int 25 | self.is_shortcut = False 26 | self.help_palette = QPalette() 27 | 28 | def decimal_point(self): 29 | return 8 30 | 31 | def numbify(self): 32 | text = unicode(self.text()).strip() 33 | if text == '!': 34 | self.shortcut.emit() 35 | return 36 | pos = self.cursorPosition() 37 | chars = '0123456789' 38 | if not self.is_int: chars +='.' 39 | s = ''.join([i for i in text if i in chars]) 40 | if not self.is_int: 41 | if '.' in s: 42 | p = s.find('.') 43 | s = s.replace('.','') 44 | s = s[:p] + '.' + s[p:p+self.decimal_point()] 45 | self.setText(s) 46 | self.setCursorPosition(pos) 47 | 48 | def paintEvent(self, event): 49 | QLineEdit.paintEvent(self, event) 50 | if self.base_unit: 51 | panel = QStyleOptionFrameV2() 52 | self.initStyleOption(panel) 53 | textRect = self.style().subElementRect(QStyle.SE_LineEditContents, panel, self) 54 | textRect.adjust(2, 0, -10, 0) 55 | painter = QPainter(self) 56 | painter.setPen(self.help_palette.brush(QPalette.Disabled, QPalette.Text).color()) 57 | painter.drawText(textRect, Qt.AlignRight | Qt.AlignVCenter, self.base_unit()) 58 | 59 | def get_amount(self): 60 | try: 61 | x = int(str(self.text())) 62 | except: 63 | return None 64 | return x 65 | 66 | 67 | class BTCAmountEdit(AmountEdit): 68 | 69 | def __init__(self, decimal_point, is_int = False, parent=None): 70 | AmountEdit.__init__(self, self._base_unit, is_int, parent) 71 | self.decimal_point = decimal_point 72 | 73 | def _base_unit(self): 74 | base_units = chainkey.chainparams.get_active_chain().base_units 75 | p = self.decimal_point() 76 | assert p in base_units.values() 77 | for k,v in base_units.iteritems(): 78 | if v == p: 79 | return k 80 | raise Exception('Unknown base unit') 81 | 82 | def get_amount(self): 83 | try: 84 | x = Decimal(str(self.text())) 85 | except: 86 | return None 87 | p = pow(10, self.decimal_point()) 88 | return int( p * x ) 89 | 90 | def setAmount(self, amount): 91 | if amount is None: 92 | self.setText("") 93 | return 94 | 95 | p = pow(10, self.decimal_point()) 96 | x = amount / Decimal(p) 97 | self.setText(str(x)) 98 | -------------------------------------------------------------------------------- /README-source.md: -------------------------------------------------------------------------------- 1 | Encompass - lightweight multi-coin client 2 | 3 | Encompass consolidates support for various currencies into one wallet. It is a BIP-0044-compliant multi-currency wallet based on Electrum. This Encompass client uses Electrum servers of supported currencies to retrieve necessary data, so no "Encompass server" is necessary. 4 | 5 | Homepage: https://maza.club/encompass 6 | 7 | ## Operation and Installation from Source 8 | * Most users are encouraged to run provided release packages for their system 9 | * Installation from source requires python knowledge, and knowledge of package managers on your system 10 | * Non-Developers wishing to compile & install from source are encouraged to use the provided build system 11 | instructions are in contrib/encompass-release/README.md 12 | 13 | 1. GETTING STARTED 14 | ------------------ 15 | 16 | Dependencies: 17 | - pyqt4 18 | - pip 19 | - modules listed in requirements.txt 20 | 21 | pyqt4 must be installed by your system package manager. 22 | pip is recommended for python module dependencies installation, 23 | 24 | * Windows 25 | - TODO 26 | * OSX 27 | - we recommend macports for installing/building Encompass 28 | ``` 29 | sudo port install py27-pyqt4 30 | sudo port install py27-pip 31 | ``` 32 | * Linux 33 | - Ubuntu 34 | ``` 35 | sudo apt-get update 36 | sudo apt-get install -y python-dev python-qt4 pyqt4-dev-tools python-pip 37 | ``` 38 | 39 | 40 | Use pip to install all dependencies: 41 | ``` 42 | pip install --upgrade -r requirements.txt 43 | ``` 44 | - OSX users please note, brew, macports, and Apple each install their own python interpreters, 45 | ensure that you use the correct version of pip. For macports this is usually in /opt/local/bin/pip-2.7 46 | 47 | Use pyrcc4 to build the icons: 48 | ``` 49 | pyrcc4 icons.qrc -o gui/qt/icons_rc.py 50 | ``` 51 | If you do not have pyrcc4 on your system, you may need to install the PyQt4-devel or pyqt4-dev-tools package first. 52 | 53 | 54 | Then to run Encompass from the source directory: 55 | ``` 56 | ./encompass 57 | ``` 58 | You can view additional debugging messages with: 59 | ``` 60 | ./encompass -v 61 | ``` 62 | 63 | If you wish to install Encompass on your system, you can run it from any 64 | directory: 65 | ``` 66 | sudo python setup.py install 67 | encompass 68 | ``` 69 | Installation from source on Linux is straightforward. 70 | Installation from source on Windows is possible, but not actively supported 71 | Installation from source on OSX is possible, users should modify ./encompass to point 72 | to the correct python installation (i.e. macports) before installation 73 | 74 | OSX users will likely find it easiest to build Encompass.app, and run that. 75 | on macports: 76 | ``` 77 | /opt/local/bin/python2.7 setup.py py2app 78 | ``` 79 | Resulting Encompass.app is found in the dist/ directory. 80 | 81 | 82 | To start Encompass from your web browser, see 83 | http://electrum.org/bitcoin_URIs.html 84 | 85 | 86 | 87 | 2. HOW OFFICIAL PACKAGES ARE CREATED 88 | ------------------------------------ 89 | 90 | See contrib/encompass-release/README.md 91 | 92 | 3. HOW COIN-SPECIFIC MODULES ARE CREATED 93 | ---------------------------------------- 94 | 95 | See lib/chains/README.md. 96 | -------------------------------------------------------------------------------- /setup-release.py: -------------------------------------------------------------------------------- 1 | """ 2 | py2app/py2exe build script for Encompass 3 | 4 | Usage (Mac OS X): 5 | python setup.py py2app 6 | 7 | Usage (Windows): 8 | python setup.py py2exe 9 | """ 10 | 11 | from setuptools import setup 12 | import os 13 | import re 14 | import shutil 15 | import sys 16 | 17 | from lib.util import print_error 18 | from lib.version import ELECTRUM_VERSION as version 19 | 20 | 21 | print_error("setup-release.py is deprecated after Encompass-0.5.0") 22 | print_error("see contrib/encompass-release/build") 23 | name = "Encompass" 24 | mainscript = 'encompass' 25 | 26 | if sys.version_info[:3] < (2, 6, 0): 27 | print_error("Error: " + name + " requires Python version >= 2.6.0...") 28 | sys.exit(1) 29 | 30 | if sys.platform == 'darwin': 31 | from plistlib import Plist 32 | plist = Plist.fromFile('Info.plist') 33 | plist.update(dict(CFBundleIconFile='encompass.icns')) 34 | 35 | shutil.copy(mainscript, mainscript + '.py') 36 | mainscript += '.py' 37 | extra_options = dict( 38 | setup_requires=['py2app'], 39 | app=[mainscript], 40 | options=dict(py2app=dict(argv_emulation=True, 41 | includes=['PyQt4.QtCore', 'PyQt4.QtGui', 'PyQt4.QtWebKit', 'PyQt4.QtNetwork', 'sip'], 42 | packages=['lib', 'gui', 'plugins'], 43 | iconfile='encompass.icns', 44 | plist=plist, 45 | resources=["data", "icons"])), 46 | ) 47 | elif sys.platform == 'win32': 48 | extra_options = dict( 49 | setup_requires=['py2exe'], 50 | app=[mainscript], 51 | ) 52 | else: 53 | extra_options = dict( 54 | # Normally unix-like platforms will use "setup.py install" 55 | # and install the main script as such 56 | scripts=[mainscript], 57 | ) 58 | 59 | setup( 60 | name=name, 61 | version=version, 62 | **extra_options 63 | ) 64 | from distutils import dir_util 65 | 66 | if sys.platform == 'darwin': 67 | # Remove the copied py file 68 | os.remove(mainscript) 69 | resource = "dist/" + name + ".app/Contents/Resources/" 70 | 71 | #dir_util.copy_tree("locale", resource + "locale/") 72 | # Try to locate qt_menu 73 | # Let's try the port version first! 74 | if os.path.isfile("/opt/local/lib/Resources/qt_menu.nib"): 75 | qt_menu_location = "/opt/local/lib/Resources/qt_menu.nib" 76 | else: 77 | # No dice? Then let's try the brew version 78 | if os.path.exists("/usr/local/Cellar"): 79 | qt_menu_location = os.popen("find /usr/local/Cellar -name qt_menu.nib | tail -n 1").read() 80 | # no brew, check /opt/local 81 | else: 82 | qt_menu_location = os.popen("find /opt/local -name qt_menu.nib | tail -n 1").read() 83 | qt_menu_location = re.sub('\n', '', qt_menu_location) 84 | 85 | if (len(qt_menu_location) == 0): 86 | print "Sorry couldn't find your qt_menu.nib this probably won't work" 87 | else: 88 | print "Found your qib: " + qt_menu_location 89 | 90 | # Need to include a copy of qt_menu.nib 91 | shutil.copytree(qt_menu_location, resource + "qt_menu.nib") 92 | # Need to touch qt.conf to avoid loading 2 sets of Qt libraries 93 | fname = resource + "qt.conf" 94 | with file(fname, 'a'): 95 | os.utime(fname, None) 96 | -------------------------------------------------------------------------------- /lib/chainparams.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | import importlib 3 | import chains 4 | # 5 | # Supported blockchains are organized in named tuples. 6 | # A ChainParams tuple contains: 7 | # chain_index: The index (BIP-0044) used in child key derivation 8 | # This is just for organization, the class of the actual 9 | # cryptocur has the chain index as well. 10 | # coin_name: Full name of the cryptocurrency 11 | # code: Abbreviated form of the cryptocurrency 12 | # module_name: Name of the module containing specifics on the cryptocur 13 | 14 | active_chain = None 15 | 16 | ChainParams = namedtuple('ChainParams', ('chain_index', 'coin_name', 'code', 'module_name')) 17 | 18 | _known_chains = ( 19 | # Bitcoin 20 | ChainParams(0, 'Bitcoin', 'BTC', 'bitcoin'), 21 | 22 | # Litecoin 23 | ChainParams(2, 'Litecoin', 'LTC', 'litecoin'), 24 | 25 | # Dash 26 | ChainParams(5, 'Dash', 'DASH', 'dash'), 27 | 28 | # Mazacoin 29 | ChainParams(13, 'Mazacoin', 'MZC', 'mazacoin'), 30 | 31 | # Viacoin 32 | ChainParams(14, 'Viacoin', 'VIA', 'viacoin'), 33 | ) 34 | 35 | _known_chain_dict = dict((i.code, i) for i in _known_chains) 36 | 37 | _known_chain_codes = [i.code for i in _known_chains] 38 | 39 | def get_active_chain(): 40 | global active_chain 41 | return active_chain 42 | 43 | def set_active_chain(chaincode): 44 | global active_chain 45 | active_chain = get_chain_instance(chaincode) 46 | 47 | def is_known_chain(code): 48 | code = code.upper() 49 | if code in _known_chain_codes: 50 | return True 51 | return False 52 | 53 | def get_params(code): 54 | code = code.upper() 55 | if code in _known_chain_codes: 56 | return _known_chain_dict[code] 57 | return None 58 | 59 | def get_chainparam(code, property): 60 | code = code.upper() 61 | chain = _known_chain_dict.get(code) 62 | if chain: 63 | return getattr(chain, property) 64 | return None 65 | 66 | def get_chain_index(code): 67 | return get_chainparam(code, 'chain_index') 68 | 69 | def get_code_from_index(index): 70 | for chain in _known_chains: 71 | if chain.chain_index == index: 72 | return chain.code 73 | return None 74 | 75 | def get_server_trust(code): 76 | '''Retrieve the relative amount of trust in this chain's servers''' 77 | instance = get_chain_instance(code) 78 | if instance is None: return None 79 | # Proof of work 80 | is_pow = instance.PoW 81 | # servers used 82 | servers = len(instance.DEFAULT_SERVERS) 83 | # criterion -> [value, info] 84 | return { 85 | 'pow': is_pow, 86 | 'servers': servers, 87 | } 88 | 89 | def get_chain_instance(code): 90 | code = code.upper() 91 | if not is_known_chain(code): return None 92 | params = get_params(code) 93 | module_name = params.module_name 94 | # If importing fails, try with a different path. 95 | try: 96 | classmodule = importlib.import_module(''.join(['chainkey.chains.', module_name])) 97 | classInst = getattr(classmodule, 'Currency') 98 | except (AttributeError, ImportError): 99 | classmodule = importlib.import_module(''.join(['lib.chains.', module_name])) 100 | classInst = getattr(classmodule, 'Currency') 101 | return classInst() 102 | -------------------------------------------------------------------------------- /contrib/ArchLinux/encompass-git/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Qhor Vertoe 2 | # Contributor: Andy Weidenbaum 3 | # Contributor: RunningDroid 4 | # Contributor: Sebastian Lindqvist 5 | 6 | pkgname=encompass-git 7 | _gitname=encompass 8 | _gitbranch="check_repo_for_correct_branch" 9 | pkgver=4216.3b91b31 10 | pkgrel=1 11 | pkgdesc="Multi-currency wallet based on Electrum. Supports Bitcoin, Litecoin, Dash, Mazacoin, Viacoin (git development version)." 12 | arch=('any') 13 | depends=('hicolor-icon-theme' 14 | 'python2' 15 | 'python2-ecdsa' 16 | 'python2-pbkdf2' 17 | 'python2-protobuf' 18 | 'python2-pyasn1' 19 | 'python2-pyasn1-modules' 20 | 'python2-pyqt4' 21 | 'python2-qrcode' 22 | 'python2-requests' 23 | 'python2-six' 24 | 'python2-slowaes' 25 | 'python2-tlslite' 26 | 'python2-socksipy-branch' 27 | 'qt4') 28 | makedepends=('gettext' 29 | 'git' 30 | 'protobuf' 31 | 'python2-pycurl' 32 | 'python2-setuptools' 33 | 'python2-pip') 34 | optdepends=('desktop-file-utils: update desktop icon' 35 | 'gtk-update-icon-cache: update desktop icon' 36 | 'python2-amodem: air-gapped transaction signing over audio modem' 37 | 'python2-btchip: BTChip hardware wallet support' 38 | 'python2-dnspython: OpenAlias plugin' 39 | 'python2-jsonrpclib: merchant script' 40 | 'python2-matplotlib: plot transaction history in graphical mode' 41 | 'python2-rpyc: send commands to Encompass Python console from an external script' 42 | 'python2-trezor: TREZOR hardware wallet support' 43 | 'xdg-utils: update desktop icon' 44 | 'zbar: QR code reading support') 45 | url="https://github.com/mazaclub/encompass" 46 | license=('GPL3') 47 | source=(git+https://github.com/mazaclub/encompass) 48 | sha256sums=('SKIP') 49 | provides=('encompass') 50 | conflicts=('encompass') 51 | install=encompass.install 52 | 53 | pkgver() { 54 | cd ${pkgname%-git} 55 | 56 | msg2 "Using '$_gitbranch' tree..." 57 | git checkout -q "$_gitbranch" 58 | git pull -q origin "$_gitbranch" 59 | echo $(git rev-list --count HEAD).$(git rev-parse --short HEAD) 60 | } 61 | 62 | prepare() { 63 | cd ${pkgname%-git} 64 | 65 | msg2 'Fixing Python version...' 66 | find . -type f -print0 | xargs -0 sed -i 's#/usr/bin/python#/usr/bin/python2#g' 67 | find . -type f -print0 | xargs -0 sed -i 's#/usr/bin/env python#/usr/bin/env python2#g' 68 | 69 | msg2 'Installing local deps from pip...' 70 | pip2 install --user ltc_scrypt 71 | pip2 install --user darkcoin_hash 72 | } 73 | 74 | build() { 75 | cd ${pkgname%-git} 76 | 77 | msg2 'Compiling icons...' 78 | pyrcc4 icons.qrc -o gui/qt/icons_rc.py 79 | 80 | msg2 'Compiling protobuf description file...' 81 | protoc --proto_path=lib/ --python_out=lib/ lib/paymentrequest.proto 82 | 83 | msg2 'Building...' 84 | python2 setup.py build 85 | } 86 | 87 | package() { 88 | cd ${pkgname%-git} 89 | 90 | msg2 'Installing...' 91 | python2 setup.py install --root="$pkgdir" --optimize=1 92 | 93 | msg2 'Cleaning up pkgdir...' 94 | find "$pkgdir" -type d -name .git -exec rm -r '{}' + 95 | find "$pkgdir" -type f -name .gitignore -exec rm -r '{}' + 96 | } 97 | -------------------------------------------------------------------------------- /lib/plugins.py: -------------------------------------------------------------------------------- 1 | from util import print_error 2 | import traceback, sys 3 | from util import * 4 | from i18n import _ 5 | 6 | plugins = [] 7 | 8 | 9 | def init_plugins(config): 10 | import imp, pkgutil, __builtin__, os 11 | global plugins 12 | 13 | if __builtin__.use_local_modules: 14 | fp, pathname, description = imp.find_module('plugins') 15 | plugin_names = [name for a, name, b in pkgutil.iter_modules([pathname])] 16 | plugin_names = filter( lambda name: os.path.exists(os.path.join(pathname,name+'.py')), plugin_names) 17 | imp.load_module('chainkey_plugins', fp, pathname, description) 18 | plugin_modules = map(lambda name: imp.load_source('chainkey_plugins.'+name, os.path.join(pathname,name+'.py')), plugin_names) 19 | else: 20 | import chainkey_plugins 21 | plugin_names = [name for a, name, b in pkgutil.iter_modules(chainkey_plugins.__path__)] 22 | plugin_modules = [ __import__('chainkey_plugins.'+name, fromlist=['chainkey_plugins']) for name in plugin_names] 23 | 24 | for name, p in zip(plugin_names, plugin_modules): 25 | try: 26 | plugins.append( p.Plugin(config, name) ) 27 | except Exception: 28 | print_msg(_("Error: cannot initialize plugin"),p) 29 | traceback.print_exc(file=sys.stdout) 30 | 31 | 32 | hook_names = set() 33 | hooks = {} 34 | 35 | def hook(func): 36 | n = func.func_name 37 | if n not in hook_names: 38 | hook_names.add(n) 39 | return func 40 | 41 | 42 | def run_hook(name, *args): 43 | results = [] 44 | f_list = hooks.get(name,[]) 45 | for p, f in f_list: 46 | if name == 'load_wallet': 47 | p.wallet = args[0] 48 | if not p.is_enabled(): 49 | continue 50 | try: 51 | r = f(*args) 52 | except Exception: 53 | print_error("Plugin error") 54 | traceback.print_exc(file=sys.stdout) 55 | r = False 56 | if r: 57 | results.append(r) 58 | 59 | if results: 60 | assert len(results) == 1, results 61 | return results[0] 62 | 63 | 64 | class BasePlugin: 65 | 66 | def __init__(self, config, name): 67 | self.name = name 68 | self.config = config 69 | # add self to hooks 70 | for k in dir(self): 71 | if k in hook_names: 72 | l = hooks.get(k, []) 73 | l.append((self, getattr(self, k))) 74 | hooks[k] = l 75 | 76 | def fullname(self): 77 | return self.name 78 | 79 | def description(self): 80 | return 'undefined' 81 | 82 | def requires_settings(self): 83 | return False 84 | 85 | def enable(self): 86 | self.set_enabled(True) 87 | return True 88 | 89 | def disable(self): 90 | self.set_enabled(False) 91 | return True 92 | 93 | def init_qt(self, gui): pass 94 | 95 | def load_wallet(self, wallet): pass 96 | 97 | #def init(self): pass 98 | 99 | def close(self): pass 100 | 101 | def is_enabled(self): 102 | return self.is_available() and self.config.get('use_'+self.name) is True 103 | 104 | def is_available(self): 105 | return True 106 | 107 | def set_enabled(self, enabled): 108 | self.config.set_key('use_'+self.name, enabled, True) 109 | 110 | def settings_dialog(self): 111 | pass 112 | -------------------------------------------------------------------------------- /lib/chains/README.md: -------------------------------------------------------------------------------- 1 | ChainKey Modules 2 | ================ 3 | 4 | This folder contains ChainKey modules for use by Encompass. A chainkey module for a coin allows Encompass to support using that coin. 5 | 6 | Basically, a chainkey module for a coin contains some code from its corresponding Electrum fork. The specific code needed is documented here, and in the abstract class CryptoCur in the file cryptocur.py. 7 | 8 | ## Writing a chainkey module 9 | 10 | ### Variables 11 | 12 | Chainkey modules require a set of constants for identifying the coin. These include: 13 | 14 | - `chain_index`: The BIP-0044 index used in HD key derivation. 15 | - `coin_name`: The full coin name, such as "Bitcoin" or "Mazacoin". 16 | - `code`: The coin's abbreviation, such as "BTC" or "MZC". 17 | - `p2pkh_version`: Address version byte, such as 0 for Bitcoin, or 50 for Mazacoin. 18 | - `p2sh_version`: Pay-To-Script-Hash version byte, such as 5 for Bitcoin, or 9 for Mazacoin. 19 | - `wif_version`: Wallet Import Format version byte, such as 128 for Bitcoin, or 224 for Mazacoin. 20 | - `DUST_THRESHOLD`: Amount of satoshis that qualify as 'dust'; 5430 for Bitcoin. 21 | - `MIN_RELAY_TX_FEE`: Minimum fee for a transaction to be relayed; 1000 for Bitcoin. 22 | - `RECOMMENDED_FEE`: Recommended transaction fee; 50000 for Bitcoin. 23 | - `COINBASE_MATURITY`: Number of blocks before mined coins are mature; 100 for Bitcoin. 24 | 25 | The following constants are not yet fully implemented, but should be included: 26 | 27 | - `ext_pub_version`: Extended public key version bytes; "0488b21e" for Bitcoin. 28 | - `ext_priv_version`: Extended private key version bytes; "0488ade4" for Bitcoin. 29 | 30 | In addition to those constants, some more modular information is required, including: 31 | 32 | - `PoW`: A boolean value expressing whether or not Proof-of-Work verification is implemented. 33 | - `block_explorers`: A dictionary of {name : URL} strings for viewing a transaction online. 34 | - `base_units`: A dictionary of {name : decimal point} units for the coin, such as "mBTC" and "BTC". 35 | 36 | Also, the number of headers in one chunk is stored in the `chunk_size` variable. This is 2016 in Electrum. 37 | 38 | Lastly, after the currency class definition, it is required to define a variable called `Currency` as the currency's class name. For example, `Currency = Bitcoin` in bitcoin.py, where the class name is "Bitcoin." 39 | 40 | ### Functions 41 | 42 | All functions for verifying headers are required in a chainkey module. Most importantly, `get_target()`, `verify_chain()`, and `verify_chunk()`, but also any functions they rely on, including `header_to_string()`, `header_from_string()`, `hash_header()`, `save_chunk()`, `save_header()`, and `read_header()`. 43 | 44 | Note that commonly in Electrum forks, the functions `save_chunk()` and `save_header()` make a call to a function `set_local_height()`. This call must be removed in the chainkey module, as `set_local_height()` is called elsewhere. Also note that any calls to `print_error()` may be removed, as importing that function is not required. 45 | 46 | If an electrum fork has a custom method to call when a chain reorg occurs, it should be included in the chainkey module class as `reorg_handler()`. 47 | 48 | ## Implementation 49 | 50 | To implement a new chain after writing a chainkey module, place the coin's module in lib/chains with the others. Then edit lib/chainparams.py, adding a ChainParams named-tuple for that coin in `_known_chains`. When a chain is in `_known_chains`, Encompass will be able to use it as long as its metadata is correct. 51 | -------------------------------------------------------------------------------- /lib/tests/test_util.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from lib.util import format_satoshis, parse_URI 3 | 4 | class TestUtil(unittest.TestCase): 5 | 6 | def test_format_satoshis(self): 7 | result = format_satoshis(1234) 8 | expected = "0.00001234" 9 | self.assertEqual(expected, result) 10 | 11 | def test_format_satoshis_diff_positive(self): 12 | result = format_satoshis(1234, is_diff=True) 13 | expected = "+0.00001234" 14 | self.assertEqual(expected, result) 15 | 16 | def test_format_satoshis_diff_negative(self): 17 | result = format_satoshis(-1234, is_diff=True) 18 | expected = "-0.00001234" 19 | self.assertEqual(expected, result) 20 | 21 | def _do_test_parse_URI(self, uri, expected_address, expected_amount, expected_label, expected_message, expected_request_url): 22 | address, amount, label, message, request_url = parse_URI(uri) 23 | self.assertEqual(expected_address, address) 24 | self.assertEqual(expected_amount, amount) 25 | self.assertEqual(expected_label, label) 26 | self.assertEqual(expected_message, message) 27 | self.assertEqual(expected_request_url, request_url) 28 | 29 | def test_parse_URI_address(self): 30 | self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', '', '', '', '') 31 | 32 | def test_parse_URI_only_address(self): 33 | self._do_test_parse_URI('15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', None, None, None, None) 34 | 35 | 36 | def test_parse_URI_address_label(self): 37 | self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?label=electrum%20test', '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', '', 'electrum test', '', '') 38 | 39 | def test_parse_URI_address_message(self): 40 | self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?message=electrum%20test', '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', '', '', 'electrum test', '') 41 | 42 | def test_parse_URI_address_amount(self): 43 | self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?amount=0.0003', '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', 30000, '', '', '') 44 | 45 | def test_parse_URI_address_request_url(self): 46 | self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?r=http://domain.tld/page?h%3D2a8628fc2fbe', '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', '', '', '', 'http://domain.tld/page?h=2a8628fc2fbe') 47 | 48 | def test_parse_URI_ignore_args(self): 49 | self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?test=test', '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', '', '', '', '') 50 | 51 | def test_parse_URI_multiple_args(self): 52 | self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?amount=0.00004&label=electrum-test&message=electrum%20test&test=none&r=http://domain.tld/page', '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', 4000, 'electrum-test', 'electrum test', 'http://domain.tld/page') 53 | 54 | def test_parse_URI_no_address_request_url(self): 55 | self._do_test_parse_URI('bitcoin:?r=http://domain.tld/page?h%3D2a8628fc2fbe', '', '', '', '', 'http://domain.tld/page?h=2a8628fc2fbe') 56 | 57 | def test_parse_URI_invalid_address(self): 58 | self.assertRaises(AssertionError, parse_URI, 'bitcoin:invalidaddress') 59 | 60 | def test_parse_URI_invalid(self): 61 | self.assertRaises(AssertionError, parse_URI, 'notbitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma') 62 | 63 | def test_parse_URI_parameter_polution(self): 64 | self.assertRaises(Exception, parse_URI, 'bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?amount=0.0003&label=test&amount=30.0') 65 | 66 | -------------------------------------------------------------------------------- /contrib/encompass-release/README.md: -------------------------------------------------------------------------------- 1 | ## Encompass Release Packaging system 2 | 3 | * Builds multiplatform release 4 | - currently, builds all supported platforms in single run 5 | - updates will include argument additions to support single-OS build, and building from develop branch 6 | 7 | * Requires either: 8 | - Linux (Ubuntu 14.04) with Docker 1.5.0 installed 9 | - OSX with boot2docker 1.5.0, and macports, with python2.7, pyqt4, and pip installed 10 | - Homebrew should also work, with some modifications (pathnames, etc) but is untested 11 | - builds using default Apple python installation are discouraged. 12 | 13 | * OSX buildhosts will build all all packages, Linux hosts are limited to building 14 | Linux, Ubuntu, and Windows packages. 15 | 16 | ### This contains the full and complete release process for Encompass as followed by mazaclub. 17 | 18 | * ** Mazaclub release packages are built via OSX in a single run with the following command: ** 19 | ``` 20 | ./build 0.5.0 SIGNED 21 | ``` 22 | This clones https://github.com/mazaclub/encompass to 23 | ``` 24 | contrib/encompass-release/repo 25 | ``` 26 | and checks out the release tag specified, then runs the build scripts. 27 | 28 | ## QuickStart 29 | ``` 30 | ./build version type 31 | ``` 32 | Types supported are: 33 | * local 34 | - build from local source - copies your local repo to a build dir, and builds 35 | * master 36 | - build from current github master 37 | * tagged 38 | - build from github tagged release 39 | * SIGNED 40 | - signed 41 | ``` 42 | ./build 0.5.0 local 43 | ``` 44 | 45 | Currently only local and SIGNED are well tested! 46 | 47 | 48 | All you need is docker to build a full release for Linux/OSX (native python) and Windows Setup.exe 49 | 50 | This contains 4 primary scripts: 51 | - build 52 | builds the docker build container, 53 | runs make_release inside this container 54 | puts all the resulting release packages and windows exe files in releases/ 55 | and finally, makes md5 and sha1 sums and gpg signs all the sums and releases 56 | 57 | - helpers/make_release 58 | gets the current requested release tag from github and packages a release 59 | 60 | - helpers/make_packages helpers/make_windows helpers/make_android 61 | performs the packaging necessary to create tarball and windows releases 62 | 63 | - helpers/build-binary 64 | builds the windows exe files 65 | 66 | To make adaptations, or for debugging/hacking simply change the $DOCKERBIN run 67 | to run /bin/bash instead of /root/make_release 68 | 69 | When the build completes, you should be left with 70 | 71 | repo/ 72 | source/ 73 | releases/ 74 | 75 | The releases/ will contain signed & summed .tar.gz .zip .exe and -setup.exe files for 76 | your release. 77 | 78 | This build should be easily adaptable to any electrum derived wallet. 79 | 80 | 81 | ##### Getting started 82 | 83 | 84 | Clone this repository and run ./build 2.0b2 (or whatever the latest stable release is) and if 85 | all goes well your windows binary should appear in the releases folder. 86 | 87 | 88 | ##### General remarks 89 | 90 | It's still a little hack-y - this is adapted from a few sources to provide a complete 91 | release packager, and intended to provide a fully deterministic build process. However, 92 | since the build script runs directly on the host, writing to the host's filesystem, 93 | and this doesn't provide the mean to specify a docker version,this is not 100% deterministic. 94 | A future update will include a vagrant box file to specify a build VM to run the build script. 95 | 96 | The script also does a little extra work as we integrate it into Encompass and our release process. 97 | 98 | There's a lot to apt-get in the Dockerfile, this will take a while to build 99 | the docker image. Once the docker image is built on your machine, the Encompass build 100 | runs quickly. 101 | 102 | 103 | -------------------------------------------------------------------------------- /pubkeys/mazaclub.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | Version: SKS 1.1.4 3 | Comment: Hostname: pgp.mit.edu 4 | 5 | mQINBFTKYcoBEADUhhewAMFwSyr8olA5ytQB2u6kw6IVZyt1uu009CSeY3XthTp33She3hM5 6 | dZNYOgWhmVanY3y/TDWfh/yyUK8XzlQTzzrrPqoIj3nCigk7KVN5/fYnaLC1IvxXY5Skfgq6 7 | UUgEQcFtnb+HejBDsupD5Gpr3JNEMbcyIMozYiJ6JLjBrY2NMlpK7Mlh4qQTVTBZO5jp6Lck 8 | HeB+kxLsavGBk0TsWMxYc4eRFQgyZ2htDKbnTtryok9NhRHt4dcyTe1IPymYwG35HY3FuuAN 9 | bf/N/1iMwKGD0xHJyibmjXbTBCsK4qq9r/GUl7m9qeXSGw4IXDXyvwNr2dixDody44FgMdXX 10 | V3UkAC1RhsM8T1iKxGX99H+HMdLz3wCJ4/edjieIA9+ZqrzHSM93os+GiBARoExNcpH+xSgE 11 | vKux+n3za0UC14tplw+nKWT+Y96FXqqQ6JXWBSQpIwJEqqvxMbGnoC22zQizcgdhIUD/paKU 12 | s55mmcQAOjGKueobCxMoqctQJaNrAC/daJS9ul4Cvm57rZhFkmF+BTzObSTZGTEXL/h40utY 13 | hiGAGEUr6LLD/0ZrLM71z4CMi4v3tvNgNM2lx/v83dsCp5yr1VjqnWhn9N/fFkZuLOb2JCkI 14 | VLUPTUkMQ9KGOgqKwmwk7BAwMnYvmjN7N8tPRGC3EiyYovivRwARAQABtEdtYXphY2x1YiBj 15 | b2RlIHNpZ25pbmcga2V5IChtYXphY2x1YiBjb2RlIHJlbGVhc2VzKSA8cmVsZWFzZXNAbWF6 16 | YS5jbHViPokCHAQQAQgABgUCVNMPjAAKCRCvArItpU6H8iQPEACNmu3Jt+vXzT8hkgO7JLLV 17 | E/4sdxpMAFbUEckfzYr27UhwK2dIxC7j49SqklIThS65abWgmSc0oL0ibPQRVgwPaCdLF9qA 18 | 9UmqpFi50uecquzsJvV9T4Im1uHDTvcHdP4L6LuMleOG121C+78GvZg1EHppop8/szQv8xUw 19 | lRGntzbcUOU47JcaOb1mPvmhTDz0d8yVlKc0fFpaK2Uhq3uzcew5X/qbW4+HQxbOe5e6WbGa 20 | zmKWL3tqtpqPiX+zTFjTRyesJVc+czJCFbDovDy+N4kh91ImcKyIpeN7XLtFhHfB8UJ9i9CS 21 | kG69kVtEiVwWYp5JfDssEyl5fFrrtagEpQEIo130NwXxw4pdizXBkBNvzWlOKrrxxDKXyw1M 22 | HTOKUNg/KqbJm6whgW55scPGMs3n95L3OWtuicQGRDcj38/er22hFJiQMhSfag3GUyOrQ0mp 23 | VZZjkw/Xg6ITqvVxU6OR6fB3XXCCny10omd7EW7qjZl5BxGl5X7Y5pzttKv/ZSQgAIMIAxqz 24 | TK9Jf15ibAkYzHzK5RocLwEoEMkUKmE+TN1mM5AsEYLvUclmzTwovM5n7LNZ/2qZGIk7LGyt 25 | KqJ5B9MV+zTeoI7gJfzMdt5NupKfOVQBYzfhOU9ZMrb3eY223dkrNZN1rkz59nWTjGVwBmQP 26 | jCiPKXZzWOiLMIkCPgQTAQIAKAUCVMphygIbAwUJAeEzgAYLCQgHAwIGFQgCCQoLBBYCAwEC 27 | HgECF4AACgkQCgICdsv/tzyerQ//YPzr6r+vnb533SXYRgsRVHiFJMI8gcleRH5CwYKxdz4e 28 | h0SPcxKwThQfBfH7sB4FH570hif30adpV1l8vYkuW27Pl7OiAubKnVKQEGJvND74LzrCuhID 29 | poHQPN/3R6vJIRUCmJPYh8zSPthRThFsH9rVo+7pRajhf8UYFwNqWgr6/txO7P63vI8hb73m 30 | o+C4sKvLlc3lxapjq/8GGsRXI9D5dFX8PxfjcXumHwOEoYx7Z9nIvrRniX6+T/rkHpa60oTh 31 | pfIjxTbcER/FqQ/VK6LBLrQ5qqoyk6bVymjmQCEfTM4DQ2/4A5uzk9PY8+2xkWz35ZvlAA6I 32 | Mkk6ARUlaKhPSmqfbi9Ny9G8HJyYmUNEzpDJSLcnDYRX/NIloLcAQ6OQMqOD7A+/xF7PqrlY 33 | UNG4uR7w4s/ttPIAFE/RXEJIpPIvR/rzDRNoX2o3wFfIpPsKFVjqNk7+J6eLvKOocbswFL2o 34 | BaCT+rZbxowOpj2BW+BFi+hZ3E5ziH//fQJLa0O2ohdC0YwxEWTkaDlIra64b8ayP49/BrsU 35 | Gc+IWoOgQ4FsRMzBKVBTU2AqjO4y3/bcrnb2k7+wJamJdX2RTNScFR2+mK/emQTBYsoaOCTz 36 | pxzVH6CXiqFnAs1M9fry/ubyXdzPQmTySQX+SkF5q0vGHECHmPXnacDRtiBE8MC5Ag0EVMph 37 | ygEQAMd+2U0p8CtoRrooa0ntBE/oBV7dskNfqUpIUbIB9rKj7R5BzzfwAwXTNGItKI3gkx+z 38 | Vy8rUi6iuRqG4xjZg3XZZt6ppJnV0HzQhG+FAzfNzhMWTAht3NU7z6pY9ZzQt1+BkkBhIF0z 39 | f3hQ7ryA5dkgzQyEuVvaTzf5oTVnaBc9b48/rN5KCTvVAyOp5EbnEz9oCBoIS/zVbE9M1XBg 40 | 8mlytbu0+8L5lB7J/EqC8ZjkD5AjsB1yjRuT6mGbGmCCvLOMRnL7zykci/Uc4QWOK0JPc8or 41 | JwuNHrXpyvSBSNim13lAFpYmxcWhexBNsd65ByerZzsykh7m+aUZS+uyJTLhklZQ9rG2ba04 42 | WExE1RBBWGZd/QTjGOj+s2VzdTrjJFhbgewOa/Xu4wVO4TsuyOIftIPWk1C5FuXgeRSN/H7c 43 | /jT9eLdUh4iswdxYbRPa/JicWlD70c4wU3tkBGjvsSwCkALdK+TSVIYZj6IvwVq9ulGMlllJ 44 | xMqi9fPlVGuaHodZ4lvZ8quEUcsf02KgvvKQ6XGDSVVOXBBvwfCWxu5UaV/lKKAWYnqZs83b 45 | WagUTK7z0iIPfhB/VVk7044kvbF8Wi7AnesnVcVuowhw+zR7g0iNYpv2NrTSlZfz6aN9oXf8 46 | Cg+QQKleMP81H+soy4WDRifSyLwZN3vxhSNdJylNABEBAAGJAiUEGAECAA8FAlTKYcoCGwwF 47 | CQHhM4AACgkQCgICdsv/tzxqfw/8DJWjExobn0C4D2ZQk/UbrDvRDVPWVJN9wMQVOT1w4iiU 48 | ASEDYD478WrE5lSKCJyA0mSSAYWYm5gHgh07C2jAdi1mZouRD6Vb6CAIj6eQK6tJSATM4n4f 49 | EodefxauhEwgQ5au8dAyLnJsRc1b9VX8FCJJ/oV2Nw8LfhiFuC2SX5pjiCFmP4Y3/HnTwUzO 50 | K1ZiMIhuojUaIiHRkRqoAPKBxpm1E/XumjvwIjtLWrOaT5J6N0mg7bZw+zi+cZVrMhAjOTGe 51 | TVc04JxKBa7p70MVjth3ZGWl4DTS73y0AJpqILFdNxleGHSJ1gWOa/tP3dXsSxF8HfI2YUcA 52 | b2GTsql5W0CL2iaqavfVGQ3WY70t5ZUUJkwSQfj1CPnDNgF/0m+AQGNHFS7rbK8sLyZz2qiC 53 | Kj1QG6HocFB43EZ9rq1mIxqllNDfuYzHRNgNPVDxmrS2+YdVRqsPKvt1R5lhC6bP+Ek3sER3 54 | Et8MejTqhYYe7d1fdrcj4RujvxGq67ahPGUU6T3/coYdBOMWMGcMivrLXsLJzk+aMiADUGmS 55 | Mmh4GB8UgtEJYVVGWOdqd+xddkcglqjYXeVVdwAqUlBr3WGE5ZtBNf+n3yu0Poh+Q6M6yLIh 56 | 5KuUMONzI3UtanuYRngkZizqkNrPtzHXAUqLq/fM3s1STfHhAUhxVA7nJcGgEEA= 57 | =h3mF 58 | -----END PGP PUBLIC KEY BLOCK----- 59 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/wip/OSX-cross/build-darwin-darkcoin_hash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | cd /code 3 | mkdir build/temp.darwin-x64 4 | mkdir build/temp.darwin-x64/sha3 5 | mkdir build/lib.darwin-x64 6 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c darkcoinmodule.c -o build/temp.darwin-x64/darkcoinmodule.o 7 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c darkcoin.c -o build/temp.darwin-x64/darkcoin.o 8 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c sha3/blake.c -o build/temp.darwin-x64/sha3/blake.o 9 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c sha3/bmw.c -o build/temp.darwin-x64/sha3/bmw.o 10 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c sha3/groestl.c -o build/temp.darwin-x64/sha3/groestl.o 11 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c sha3/jh.c -o build/temp.darwin-x64/sha3/jh.o 12 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c sha3/keccak.c -o build/temp.darwin-x64/sha3/keccak.o 13 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c sha3/skein.c -o build/temp.darwin-x64/sha3/skein.o 14 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c sha3/cubehash.c -o build/temp.darwin-x64/sha3/cubehash.o 15 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c sha3/echo.c -o build/temp.darwin-x64/sha3/echo.o 16 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c sha3/luffa.c -o build/temp.darwin-x64/sha3/luffa.o 17 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c sha3/simd.c -o build/temp.darwin-x64/sha3/simd.o 18 | x86_64-apple-darwin14-cc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I./sha3 -I/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/include/python2.7/ -c sha3/shavite.c -o build/temp.darwin-x64/sha3/shavite.o 19 | x86_64-apple-darwin14-cc -shared -lpython -L/usr/x86_64-apple-darwin14/SDK/MacOSX10.10.sdk/usr/lib/ -L/usr/x86_64-apple-darwin14/lib -Bsymbolic-functions -Bsymbolic-functions -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -D_FORTIFY_SOURCE=2 -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security build/temp.darwin-x64/darkcoinmodule.o build/temp.darwin-x64/darkcoin.o build/temp.darwin-x64/sha3/blake.o build/temp.darwin-x64/sha3/bmw.o build/temp.darwin-x64/sha3/groestl.o build/temp.darwin-x64/sha3/jh.o build/temp.darwin-x64/sha3/keccak.o build/temp.darwin-x64/sha3/skein.o build/temp.darwin-x64/sha3/cubehash.o build/temp.darwin-x64/sha3/echo.o build/temp.darwin-x64/sha3/luffa.o build/temp.darwin-x64/sha3/simd.o build/temp.darwin-x64/sha3/shavite.o -o build/lib.darwin-x64/darkcoin_hash.dylib 20 | 21 | -------------------------------------------------------------------------------- /gui/qt/qrcodewidget.py: -------------------------------------------------------------------------------- 1 | from PyQt4.QtGui import * 2 | from PyQt4.QtCore import * 3 | import PyQt4.QtCore as QtCore 4 | import PyQt4.QtGui as QtGui 5 | 6 | import os 7 | import qrcode 8 | 9 | import chainkey 10 | from chainkey import bmp 11 | from chainkey.i18n import _ 12 | 13 | 14 | class QRCodeWidget(QWidget): 15 | 16 | def __init__(self, data = None, fixedSize=False): 17 | QWidget.__init__(self) 18 | self.data = None 19 | self.qr = None 20 | self.fixedSize=fixedSize 21 | if fixedSize: 22 | self.setFixedSize(fixedSize, fixedSize) 23 | self.setData(data) 24 | 25 | 26 | def setData(self, data): 27 | if self.data != data: 28 | self.data = data 29 | if self.data: 30 | self.qr = qrcode.QRCode() 31 | self.qr.add_data(self.data) 32 | if not self.fixedSize: 33 | k = len(self.qr.get_matrix()) 34 | self.setMinimumSize(k*5,k*5) 35 | else: 36 | self.qr = None 37 | 38 | self.update() 39 | 40 | 41 | def paintEvent(self, e): 42 | if not self.data: 43 | return 44 | 45 | black = QColor(0, 0, 0, 255) 46 | white = QColor(255, 255, 255, 255) 47 | 48 | if not self.qr: 49 | qp = QtGui.QPainter() 50 | qp.begin(self) 51 | qp.setBrush(white) 52 | qp.setPen(white) 53 | r = qp.viewport() 54 | qp.drawRect(0, 0, r.width(), r.height()) 55 | qp.end() 56 | return 57 | 58 | matrix = self.qr.get_matrix() 59 | k = len(matrix) 60 | qp = QtGui.QPainter() 61 | qp.begin(self) 62 | r = qp.viewport() 63 | 64 | margin = 10 65 | framesize = min(r.width(), r.height()) 66 | boxsize = int( (framesize - 2*margin)/k ) 67 | size = k*boxsize 68 | left = (r.width() - size)/2 69 | top = (r.height() - size)/2 70 | 71 | # Make a white margin around the QR in case of dark theme use 72 | qp.setBrush(white) 73 | qp.setPen(white) 74 | qp.drawRect(left-margin, top-margin, size+(margin*2), size+(margin*2)) 75 | 76 | for r in range(k): 77 | for c in range(k): 78 | if matrix[r][c]: 79 | qp.setBrush(black) 80 | qp.setPen(black) 81 | else: 82 | qp.setBrush(white) 83 | qp.setPen(white) 84 | qp.drawRect(left+c*boxsize, top+r*boxsize, boxsize, boxsize) 85 | qp.end() 86 | 87 | 88 | 89 | class QRDialog(QDialog): 90 | 91 | def __init__(self, data, parent=None, title = "", show_text=False): 92 | QDialog.__init__(self, parent) 93 | 94 | d = self 95 | d.setWindowTitle(title) 96 | vbox = QVBoxLayout() 97 | qrw = QRCodeWidget(data) 98 | vbox.addWidget(qrw, 1) 99 | if show_text: 100 | text = QTextEdit() 101 | text.setText(data) 102 | text.setReadOnly(True) 103 | vbox.addWidget(text) 104 | hbox = QHBoxLayout() 105 | hbox.addStretch(1) 106 | 107 | config = chainkey.get_config() 108 | if config: 109 | filename = os.path.join(config.path, "qrcode.bmp") 110 | 111 | def print_qr(): 112 | bmp.save_qrcode(qrw.qr, filename) 113 | QMessageBox.information(None, _('Message'), _("QR code saved to file") + " " + filename, _('OK')) 114 | 115 | def copy_to_clipboard(): 116 | bmp.save_qrcode(qrw.qr, filename) 117 | QApplication.clipboard().setImage(QImage(filename)) 118 | QMessageBox.information(None, _('Message'), _("QR code saved to clipboard"), _('OK')) 119 | 120 | b = QPushButton(_("Copy")) 121 | hbox.addWidget(b) 122 | b.clicked.connect(copy_to_clipboard) 123 | 124 | b = QPushButton(_("Save")) 125 | hbox.addWidget(b) 126 | b.clicked.connect(print_qr) 127 | 128 | b = QPushButton(_("Close")) 129 | hbox.addWidget(b) 130 | b.clicked.connect(d.accept) 131 | b.setDefault(True) 132 | 133 | vbox.addLayout(hbox) 134 | d.setLayout(vbox) 135 | -------------------------------------------------------------------------------- /gui/qt/seed_dialog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Electrum - lightweight Bitcoin client 4 | # Copyright (C) 2013 ecdsa@github 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from PyQt4.QtGui import * 20 | from PyQt4.QtCore import * 21 | import PyQt4.QtCore as QtCore 22 | from chainkey.i18n import _ 23 | from chainkey import mnemonic 24 | from qrcodewidget import QRCodeWidget, QRDialog 25 | from util import close_button 26 | from qrtextedit import ShowQRTextEdit, ScanQRTextEdit 27 | 28 | class SeedDialog(QDialog): 29 | def __init__(self, parent, seed, imported_keys): 30 | QDialog.__init__(self, parent) 31 | self.setModal(1) 32 | self.setMinimumWidth(400) 33 | self.setWindowTitle('Encompass' + ' - ' + _('Seed')) 34 | vbox = show_seed_box(seed) 35 | if imported_keys: 36 | vbox.addWidget(QLabel(""+_("WARNING")+": " + _("Your wallet contains imported keys. These keys cannot be recovered from seed.") + "

")) 37 | vbox.addLayout(close_button(self)) 38 | self.setLayout(vbox) 39 | 40 | 41 | def icon_filename(sid): 42 | if sid == 'cold': 43 | return ":icons/cold_seed.png" 44 | elif sid == 'hot': 45 | return ":icons/hot_seed.png" 46 | else: 47 | return ":icons/seed.png" 48 | 49 | 50 | 51 | 52 | def show_seed_box(seed, sid=None): 53 | 54 | save_msg = _("Please save these %d words on paper (order is important).")%len(seed.split()) + " " 55 | qr_msg = _("Your seed is also displayed as QR code, in case you want to transfer it to a mobile phone.") + "

" 56 | warning_msg = ""+_("WARNING")+": " + _("Never disclose your seed. Never type it on a website.") + "

" 57 | 58 | if sid is None: 59 | msg = _("Your wallet generation seed is") 60 | msg2 = save_msg + " " \ 61 | + _("This seed will allow you to recover your wallet in case of computer failure.") + "
" \ 62 | + warning_msg 63 | 64 | elif sid == 'cold': 65 | msg = _("Your cold storage seed is") 66 | msg2 = save_msg + " " \ 67 | + _("This seed will be permanently deleted from your wallet file. Make sure you have saved it before you press 'next'") + " " \ 68 | 69 | elif sid == 'hot': 70 | msg = _("Your hot seed is") 71 | msg2 = save_msg + " " \ 72 | + _("If you ever need to recover your wallet from seed, you will need both this seed and your cold seed.") + " " \ 73 | 74 | label1 = QLabel(msg+ ":") 75 | seed_text = ShowQRTextEdit(text=seed) 76 | seed_text.setMaximumHeight(130) 77 | 78 | label2 = QLabel(msg2) 79 | label2.setWordWrap(True) 80 | 81 | logo = QLabel() 82 | logo.setPixmap(QPixmap(icon_filename(sid)).scaledToWidth(56)) 83 | logo.setMaximumWidth(60) 84 | 85 | grid = QGridLayout() 86 | grid.addWidget(logo, 0, 0) 87 | grid.addWidget(label1, 0, 1) 88 | grid.addWidget(seed_text, 1, 0, 1, 2) 89 | vbox = QVBoxLayout() 90 | vbox.addLayout(grid) 91 | vbox.addWidget(label2) 92 | vbox.addStretch(1) 93 | 94 | return vbox 95 | 96 | 97 | def enter_seed_box(msg, window, sid=None): 98 | vbox = QVBoxLayout() 99 | logo = QLabel() 100 | logo.setPixmap(QPixmap(icon_filename(sid)).scaledToWidth(56)) 101 | logo.setMaximumWidth(60) 102 | 103 | label = QLabel(msg) 104 | label.setWordWrap(True) 105 | 106 | seed_e = ScanQRTextEdit(win=window) 107 | seed_e.setMaximumHeight(100) 108 | seed_e.setTabChangesFocus(True) 109 | 110 | vbox.addWidget(label) 111 | 112 | grid = QGridLayout() 113 | grid.addWidget(logo, 0, 0) 114 | grid.addWidget(seed_e, 0, 1) 115 | 116 | vbox.addLayout(grid) 117 | return vbox, seed_e 118 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/make_release: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -xeo pipefail 3 | export VERSION="$1" 4 | export BUILDTYPE="${2:-tagged}" 5 | 6 | 7 | die () { 8 | case $1 in 9 | 1) echo "Build Error:" 10 | echo "Build Version: ${VERSION} and git Version: ${gitver} don't match" 11 | echo "Bump version or build from master with ./build ${VERSION} master" 12 | exit 1 13 | ;; 14 | 2) echo "git checkout failed" 15 | echo "Didnt find TAG for ${VERSION}" 16 | exit 2 17 | ;; 18 | 3) echo "setup.py not found in /root/repo" 19 | echo "maybe your source dir was empty?" 20 | exit 3 21 | ;; 22 | *) echo "ERROR: die called exit $1" 23 | exit "$1" 24 | ;; 25 | esac 26 | } 27 | check_ver () { 28 | export gitver=$(grep "ELECTRUM_VERSION" lib/version.py |awk '{print $3}' |cut -d"\"" -f2) 29 | if [ "${VERSION}" != "${gitver}" ] 30 | then 31 | sed -i 's/ELECTRUM_VERSION\ \=\ \"'${gitver}'\"/ELECTRUM_VERSION\ \=\ \"'${VERSION}'\"/g' lib/version.py 32 | fi 33 | } 34 | 35 | install_pip () { 36 | ## install dependencies to build environment 37 | pip install --upgrade --no-compile -t packages -r /root/requirements.txt 38 | pip install --upgrade -r /root/requirements.txt 39 | 40 | } 41 | 42 | cd /root 43 | ### make release tarballs/zips 44 | if [ "${BUILDTYPE}" = "master" ] 45 | then 46 | echo "building from MASTER" 47 | git clone https://github.com/mazaclub/encompass repo 48 | cd /root/repo 49 | check_ver 50 | elif [ "${BUILDTYPE}" = "local" ] 51 | then 52 | cd /root/repo 53 | test -f /root/repo/setup.py || die 3 54 | echo "Building from local sources as Version ${VERSION}" 55 | check_ver 56 | elif [ "${BUILDTYPE}" = "rc" ] 57 | then 58 | git clone https://github.com/mazaclub/encompass repo 59 | cd /root/repo 60 | git checkout release/v${VERSION} || die 2 61 | 62 | else "Building from Tagged Version: ${VERSION}" 63 | git clone https://github.com/mazaclub/encompass repo 64 | cd /root/repo 65 | git checkout v"${VERSION}" || die 2 66 | fi 67 | cp -v /root/make_packages /root/repo/make_packages 68 | cp -v /root/make_android /root/repo/make_android 69 | cp -v /root/make_windows /root/repo/make_windows 70 | test -d /root/release-packages || mkdir /root/release-packages 71 | mkdir ./packages 72 | install_pip 73 | pyrcc4 icons.qrc -o gui/qt/icons_rc.py 74 | python setup.py install 75 | 76 | echo "Making Source" 77 | #cp -av /root/ltc_scrypt.so lib/ 78 | #cp -av /root/darkcoin_hash.so lib/ 79 | cp -av /root/packages ./ 80 | ./make_packages 81 | test -d /root/release-packages/Source || mkdir -pv /root/release-packages/Source 82 | cp -av dist/* /root/release-packages/Source 83 | rm -rf dist/* 84 | echo "Source Complete...." 85 | 86 | #echo "Making Android" 87 | #cp -av /root/packages ./ 88 | #cp -av /root/ltc_scrypt.so lib/ 89 | #cp -av /root/darkcoin_hash.so lib/ 90 | 91 | #./make_android 92 | #test -d /root/release-packages/Android || mkdir -pv /root/release-packages/Android 93 | #cp -av dist/* /root/release-packages/Android 94 | #rm -rf dist/* 95 | #echo "Android complete...." 96 | 97 | echo "Making Windows" 98 | cp -av /root/packages ./ 99 | cp -av /root/trezorctl.py ./packages/ 100 | ./make_windows 101 | test -d /root/release-packages/Windows || mkdir -pv /root/release-packages/Windows 102 | rm -rf /opt/wine-electrum/drive_c/encompass/Encompass-"$VERSION".* 103 | rm -rf /opt/wine-electrum/drive_c/encompass/Encompass-"$VERSION"/ 104 | rm -rf /opt/wine-electrum/drive_c/encompass/Encompass-"$VERSION"* 105 | cp -v /root/repo/dist/Encompass-"$VERSION".zip /opt/wine-electrum/drive_c/encompass/Encompass-"$VERSION".zip 106 | cp -av dist/* /root/release-packages/Windows 107 | ## FIXME put buildbinary here 108 | #mv /opt/wine-electrum/drive_c/encompass/Encompass-${VERSION}/dist/encompass-setup.exe /root/release-packages/Windows/Encompass-${VERSION}-Windows-setup.exe 109 | #mv /opt/wine-electrum/drive_c/encompass/Encompass-${VERSION}/dist/encompass.exe /root/release-packages/Windows/Encompass-${VERSION}-Windows.exe 110 | ## rm just isn't that expensive to run without fancy bash expansions 111 | cd /opt/wine-electrum/drive_c/encompass 112 | unzip Encompass-"$VERSION".zip 113 | cp -av /root/darkcoin_hash.pyd /opt/wine-electrum/drive_c/encompass/Encompass-"$VERSION"/lib 114 | cp -av /root/ltc_scrypt.pyd /opt/wine-electrum/drive_c/encompass/Encompass-"$VERSION"/lib 115 | cp -av /root/hid.pyd /opt/wine-electrum/drive_c/encompass/Encompass-"${VERSION}"/lib 116 | cp -av /root/hid.pyd /opt/wine-electrum/drive_c/encompass/Encompass-"${VERSION}" 117 | echo "Windows Complete" 118 | 119 | 120 | echo "$0 for ${VERSION}:${BUILDTYPE} completed" 121 | -------------------------------------------------------------------------------- /plugins/greenaddress_instant.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Electrum - lightweight Bitcoin client 4 | # Copyright (C) 2014 Thomas Voegtlin 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import urllib 20 | import httplib 21 | import json 22 | import sys 23 | 24 | from PyQt4.QtGui import QMessageBox, QApplication, QPushButton 25 | 26 | from chainkey.account import BIP32_Account 27 | from chainkey import bitcoin, util 28 | from chainkey import transaction 29 | from chainkey.plugins import BasePlugin, hook 30 | from chainkey.i18n import _ 31 | from chainkey.bitcoin import regenerate_key 32 | 33 | 34 | description = _("Allows validating if your transactions have instant confirmations by GreenAddress") 35 | 36 | 37 | class Plugin(BasePlugin): 38 | 39 | button_label = _("Verify GA instant") 40 | 41 | def fullname(self): 42 | return 'GreenAddress instant' 43 | 44 | def description(self): 45 | return description 46 | 47 | def is_available(self): 48 | # Disabled until compatibility is ensured 49 | return False 50 | 51 | @hook 52 | def init_qt(self, gui): 53 | self.win = gui.main_window 54 | 55 | @hook 56 | def transaction_dialog(self, d): 57 | self.wallet = d.wallet 58 | self.verify_button = b = QPushButton(self.button_label) 59 | b.clicked.connect(lambda: self.do_verify(d.tx)) 60 | d.buttons.insertWidget(2, b) 61 | self.transaction_dialog_update(d) 62 | 63 | def get_my_addr(self, tx): 64 | """Returns the address for given tx which can be used to request 65 | instant confirmation verification from GreenAddress""" 66 | 67 | for addr, _ in tx.get_outputs(): 68 | if self.wallet.is_mine(addr): 69 | return addr 70 | return None 71 | 72 | @hook 73 | def transaction_dialog_update(self, d): 74 | if d.tx.is_complete() and self.get_my_addr(d.tx): 75 | self.verify_button.show() 76 | else: 77 | self.verify_button.hide() 78 | 79 | def do_verify(self, tx): 80 | # 1. get the password and sign the verification request 81 | password = None 82 | if self.wallet.use_encryption: 83 | msg = _('GreenAddress requires your signature to verify that transaction is instant.\n' 84 | 'Please enter your password to sign a verification request.') 85 | password = self.win.password_dialog(msg) 86 | if not password: 87 | return 88 | try: 89 | self.verify_button.setText(_('Verifying...')) 90 | QApplication.processEvents() # update the button label 91 | 92 | addr = self.get_my_addr(tx) 93 | message = "Please verify if %s is GreenAddress instant confirmed" % tx.hash() 94 | sig = self.wallet.sign_message(addr, message, password) 95 | 96 | # 2. send the request 97 | connection = httplib.HTTPSConnection('greenaddress.it') 98 | connection.request("GET", ("/verify/?signature=%s&txhash=%s" % (urllib.quote(sig), tx.hash())), 99 | None, {'User-Agent': 'Electrum'}) 100 | response = connection.getresponse() 101 | response = json.loads(response.read()) 102 | 103 | # 3. display the result 104 | if response.get('verified'): 105 | QMessageBox.information(None, _('Verification successful!'), 106 | _('%s is covered by GreenAddress instant confirmation') % (tx.hash()), _('OK')) 107 | else: 108 | QMessageBox.critical(None, _('Verification failed!'), 109 | _('%s is not covered by GreenAddress instant confirmation') % (tx.hash()), _('OK')) 110 | except BaseException as e: 111 | import traceback 112 | traceback.print_exc(file=sys.stdout) 113 | QMessageBox.information(None, _('Error'), str(e), _('OK')) 114 | finally: 115 | self.verify_button.setText(self.button_label) 116 | -------------------------------------------------------------------------------- /contrib/encompass-release/helpers/linux_installer.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | error() { 3 | printf '\E[31m'; echo "$@"; printf '\E[0m' 4 | } 5 | success_msg (){ 6 | printf '\E[32m'; echo "$@"; printf '\E[0m' 7 | } 8 | 9 | 10 | if [[ $EUID -eq 0 ]]; then 11 | error "This script should not be run using sudo or as the root user" 12 | exit 1 13 | fi 14 | PREFIX="/" 15 | 16 | echo "" 17 | echo "Encompass-ELECTRUM_VERSION for Linux-x86_64" 18 | echo "by mazaclub - Lead Author, Tyler Willis, release manager, Rob Nelson" 19 | echo "" 20 | echo "based on Electrum, By Thomas Voegtlin" 21 | echo "Global install Requires root privileges, installs Encompass" 22 | echo "" 23 | echo "Extracting file into /tmp/Encompass-ELECTRUM_VERSION" 24 | SKIP=`awk '/^__TARFILE_FOLLOWS__/ { print NR + 1; exit 0; }' $0` 25 | 26 | #remember our file name 27 | THIS=`pwd`/$0 28 | 29 | # take the tarfile and pipe it into tar 30 | tail -n +$SKIP $THIS | tar -C /tmp -xpvz 31 | 32 | # Any script here will happen after the tar file extract. 33 | success (){ 34 | cat /tmp/Encompass-ELECTRUM_VERSION/README-Linux-x86_64.md 35 | success_msg "Encompass-ELECTRUM_VERSION is installed to ${DIR} - start script in ${BINDIR}" 36 | error "Remember to save your seeds in a safe place!!" 37 | success_msg "Finished" 38 | exit 0 39 | } 40 | 41 | check_arch (){ 42 | if [ "$(uname -p)" != "x86_64" ] 43 | then 44 | error "Encompass for Linux supports x86_64 machines only" 45 | error "You're recommended to use a source installation:" 46 | error "git clone https://github.com/mazaclub/encompass" 47 | error "cd encompass" 48 | error "git checkout ELECTRUM_VERSION" 49 | error "pyrcc4 icons.prc -o gui/qt/icons_qrc.py" 50 | error "sudo apt-get install python-qt4 pip" 51 | error "sudo pip install --upgrade -r requirements.txt" 52 | error "sudo python setup.py install" 53 | exit 2 54 | fi 55 | } 56 | 57 | install_encompass() { 58 | cat /tmp/Encompass-ELECTRUM_VERSION/LICENSE 59 | success_msg "Installing to ${DIR}/encompass" \ 60 | && test -d ${DIR} || ${SUDO} mkdir -p ${DIR} \ 61 | && test -d ${BINDIR} || ${SUDO} mkdir -p ${BINDIR} \ 62 | && ${SUDO} mkdir -p ${SHAREDIR}/app-install/icons \ 63 | && ${SUDO} cp /tmp/Encompass-ELECTRUM_VERSION/encompass.png ${SHAREDIR}/app-install/icons/encompass.png \ 64 | && ${SUDO} mkdir -pv ${DIR}/encompass \ 65 | && ${SUDO} cp -a /tmp/Encompass-ELECTRUM_VERSION/encompass ${DIR} \ 66 | && seddir=$(echo "${DIR}" | sed 's/\//\\\//g') \ 67 | && sed -e 's/INSTALL_DIR/'${seddir}'/g' /tmp/Encompass-ELECTRUM_VERSION/encompass.sh > /tmp/Encompass-ELECTRUM_VERSION/encompass-bindir.sh \ 68 | && ${SUDO} mv /tmp/Encompass-ELECTRUM_VERSION/encompass-bindir.sh ${BINDIR}/encompass \ 69 | && ${SUDO} chmod 555 ${BINDIR}/encompass \ 70 | && ${SUDO} cp /tmp/Encompass-ELECTRUM_VERSION/encompass.desktop ${SHAREDIR}/applications/ \ 71 | && success_msg "Encompass-ELECTRUM_VERSION installation successful" \ 72 | && success_msg "To start encompass run ${DIR}/encompass/encompass " \ 73 | && success_msg "Your wallets will be in ${HOME}/.encompass/wallets" \ 74 | && if [ "${SUDO}X" = "X" ] ; then 75 | echo "You might wish to add ${HOME}/encompass to your PATH" 76 | echo "and copy ${HOME}/encompass/90-trezor.rules to /etc/udev/rules.d" 77 | else 78 | ${SUDO} cp /tmp/Encompass-ELECTRUM_VERSION/90-trezor.rules /etc/udev/rules.d 79 | fi \ 80 | && success 81 | } 82 | 83 | get_config () { 84 | cd /tmp/Encompass-ELECTRUM_VERSION 85 | success_msg "Encompass has been extracted to /tmp/Encompass-ELECTRUM_VERSION" 86 | echo "This install script will be available at /tmp/Encompass/ELECTRUM_VERSION/linux_installer.sh" 87 | echo " " 88 | echo "Would you like to install Encompass to:" 89 | echo "1) /opt/encompass" 90 | echo "2) $HOME/encompass" 91 | echo "3) Bail - Don't install Encompass!" 92 | read dir 93 | case ${dir} in 94 | 1) export DIR="/opt" 95 | BINDIR="/usr/local/bin" 96 | SHAREDIR="/usr/share" 97 | SUDO="sudo" 98 | install_encompass 99 | ;; 100 | 2) export DIR="${HOME}" 101 | SUDO="" 102 | BINDIR="${HOME}/encompass" 103 | SHAREDIR="${HOME}/.local/share" 104 | install_encompass 105 | ;; 106 | 3) error "Not installing encompass" 107 | error "You can view encompass in /tmp/Encompass-ELECTRUM_VERSION" 108 | error "Along with the full contents of this installer." 109 | exit 0 110 | ;; 111 | *) error "Please choose 1, 2, or 3" 112 | get_config 113 | ;; 114 | esac 115 | } 116 | error "Installing Encompass-ELECTRUM_VERSION" 117 | echo "" 118 | check_arch 119 | get_config 120 | 121 | error "Install appears to have failed - please ensure you have root permissions and try again" 122 | exit 1 123 | 124 | # NOTE: Don't place any newline characters after the last line below. 125 | __TARFILE_FOLLOWS__ 126 | -------------------------------------------------------------------------------- /gui/qt/version_getter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Electrum - lightweight Bitcoin client 4 | # Copyright (C) 2012 thomasv@gitorious 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import threading, httplib, re, socket 20 | import webbrowser 21 | from PyQt4.QtGui import * 22 | from PyQt4.QtCore import * 23 | import PyQt4.QtCore as QtCore 24 | 25 | from chainkey.i18n import _ 26 | from chainkey import ELECTRUM_VERSION, print_error 27 | 28 | class VersionGetter(threading.Thread): 29 | 30 | def __init__(self, label): 31 | threading.Thread.__init__(self) 32 | self.label = label 33 | 34 | def run(self): 35 | try: 36 | con = httplib.HTTPConnection('electrum.org', 80, timeout=5) 37 | con.request("GET", "/version") 38 | res = con.getresponse() 39 | except socket.error as msg: 40 | print_error("Could not retrieve version information") 41 | return 42 | 43 | if res.status == 200: 44 | latest_version = res.read() 45 | latest_version = latest_version.replace("\n","") 46 | if(re.match('^\d+(\.\d+)*$', latest_version)): 47 | self.label.callback(latest_version) 48 | 49 | class UpdateLabel(QLabel): 50 | def __init__(self, config, sb): 51 | QLabel.__init__(self) 52 | self.new_version = False 53 | self.sb = sb 54 | self.config = config 55 | self.current_version = ELECTRUM_VERSION 56 | self.connect(self, QtCore.SIGNAL('new_electrum_version'), self.new_electrum_version) 57 | # prevent HTTP leaks if a proxy is set 58 | if self.config.get('proxy'): 59 | return 60 | VersionGetter(self).start() 61 | 62 | def callback(self, version): 63 | self.latest_version = version 64 | if(self.compare_versions(self.latest_version, self.current_version) == 1): 65 | latest_seen = self.config.get("last_seen_version",ELECTRUM_VERSION) 66 | if(self.compare_versions(self.latest_version, latest_seen) == 1): 67 | self.new_version = True 68 | self.emit(QtCore.SIGNAL('new_electrum_version')) 69 | 70 | def new_electrum_version(self): 71 | if self.new_version: 72 | self.setText(_("New version available") + ": " + self.latest_version) 73 | self.sb.insertPermanentWidget(1, self) 74 | 75 | def compare_versions(self, version1, version2): 76 | def normalize(v): 77 | return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")] 78 | return cmp(normalize(version1), normalize(version2)) 79 | 80 | def ignore_this_version(self): 81 | self.setText("") 82 | self.config.set_key("last_seen_version", self.latest_version, True) 83 | QMessageBox.information(self, _("Preference saved"), _("Notifications about this update will not be shown again.")) 84 | self.dialog.done(0) 85 | 86 | def ignore_all_version(self): 87 | self.setText("") 88 | self.config.set_key("last_seen_version", "9.9.9", True) 89 | QMessageBox.information(self, _("Preference saved"), _("No more notifications about version updates will be shown.")) 90 | self.dialog.done(0) 91 | 92 | def open_website(self): 93 | webbrowser.open("http://electrum.org/download.html") 94 | self.dialog.done(0) 95 | 96 | def mouseReleaseEvent(self, event): 97 | dialog = QDialog(self) 98 | dialog.setWindowTitle(_('Encompass update')) 99 | dialog.setModal(1) 100 | 101 | main_layout = QGridLayout() 102 | main_layout.addWidget(QLabel(_("A new version of Encompass is available:")+" " + self.latest_version), 0,0,1,3) 103 | 104 | ignore_version = QPushButton(_("Ignore this version")) 105 | ignore_version.clicked.connect(self.ignore_this_version) 106 | 107 | ignore_all_versions = QPushButton(_("Ignore all versions")) 108 | ignore_all_versions.clicked.connect(self.ignore_all_version) 109 | 110 | open_website = QPushButton(_("Goto download page")) 111 | open_website.clicked.connect(self.open_website) 112 | 113 | main_layout.addWidget(ignore_version, 1, 0) 114 | main_layout.addWidget(ignore_all_versions, 1, 1) 115 | main_layout.addWidget(open_website, 1, 2) 116 | 117 | dialog.setLayout(main_layout) 118 | 119 | self.dialog = dialog 120 | 121 | if not dialog.exec_(): return 122 | -------------------------------------------------------------------------------- /plugins/plot.py: -------------------------------------------------------------------------------- 1 | from PyQt4.QtGui import * 2 | from chainkey.plugins import BasePlugin, hook 3 | from chainkey.i18n import _ 4 | 5 | 6 | import datetime 7 | from chainkey.util import format_satoshis 8 | 9 | 10 | try: 11 | import matplotlib.pyplot as plt 12 | import matplotlib.dates as md 13 | from matplotlib.patches import Ellipse 14 | from matplotlib.offsetbox import AnchoredOffsetbox, TextArea, DrawingArea, HPacker 15 | flag_matlib=True 16 | except: 17 | flag_matlib=False 18 | 19 | 20 | 21 | 22 | 23 | class Plugin(BasePlugin): 24 | 25 | 26 | def fullname(self): 27 | return 'Plot History' 28 | 29 | def description(self): 30 | return '%s\n%s' % (_("Ability to plot transaction history in graphical mode."), _("Warning: Requires matplotlib library.")) 31 | 32 | def is_available(self): 33 | # Disabled until compatibility is ensured 34 | return False 35 | if flag_matlib: 36 | return True 37 | else: 38 | return False 39 | 40 | 41 | 42 | def is_enabled(self): 43 | if not self.is_available(): 44 | return False 45 | else: 46 | return True 47 | 48 | 49 | @hook 50 | def init_qt(self, gui): 51 | self.win = gui.main_window 52 | 53 | @hook 54 | def export_history_dialog(self, d,hbox): 55 | self.wallet = d.wallet 56 | 57 | history = self.wallet.get_tx_history() 58 | 59 | if len(history) > 0: 60 | b = QPushButton(_("Preview plot")) 61 | hbox.addWidget(b) 62 | b.clicked.connect(lambda: self.do_plot(self.wallet)) 63 | else: 64 | b = QPushButton(_("No history to plot")) 65 | hbox.addWidget(b) 66 | 67 | 68 | 69 | def do_plot(self,wallet): 70 | history = wallet.get_tx_history() 71 | balance_Val=[] 72 | fee_val=[] 73 | value_val=[] 74 | datenums=[] 75 | unknown_trans=0 76 | pending_trans=0 77 | counter_trans=0 78 | for item in history: 79 | tx_hash, confirmations, is_mine, value, fee, balance, timestamp = item 80 | if confirmations: 81 | if timestamp is not None: 82 | try: 83 | datenums.append(md.date2num(datetime.datetime.fromtimestamp(timestamp))) 84 | balance_string = format_satoshis(balance, False) 85 | balance_Val.append(float((format_satoshis(balance,False)))*1000.0) 86 | except [RuntimeError, TypeError, NameError] as reason: 87 | unknown_trans=unknown_trans+1 88 | pass 89 | else: 90 | unknown_trans=unknown_trans+1 91 | else: 92 | pending_trans=pending_trans+1 93 | 94 | if value is not None: 95 | value_string = format_satoshis(value, True) 96 | value_val.append(float(value_string)*1000.0) 97 | else: 98 | value_string = '--' 99 | 100 | if fee is not None: 101 | fee_string = format_satoshis(fee, True) 102 | fee_val.append(float(fee_string)) 103 | else: 104 | fee_string = '0' 105 | 106 | if tx_hash: 107 | label, is_default_label = wallet.get_label(tx_hash) 108 | label = label.encode('utf-8') 109 | else: 110 | label = "" 111 | 112 | 113 | f, axarr = plt.subplots(2, sharex=True) 114 | 115 | plt.subplots_adjust(bottom=0.2) 116 | plt.xticks( rotation=25 ) 117 | ax=plt.gca() 118 | x=19 119 | test11="Unknown transactions = "+str(unknown_trans)+" Pending transactions = "+str(pending_trans)+" ." 120 | box1 = TextArea(" Test : Number of pending transactions", textprops=dict(color="k")) 121 | box1.set_text(test11) 122 | 123 | 124 | box = HPacker(children=[box1], 125 | align="center", 126 | pad=0.1, sep=15) 127 | 128 | anchored_box = AnchoredOffsetbox(loc=3, 129 | child=box, pad=0.5, 130 | frameon=True, 131 | bbox_to_anchor=(0.5, 1.02), 132 | bbox_transform=ax.transAxes, 133 | borderpad=0.5, 134 | ) 135 | 136 | 137 | ax.add_artist(anchored_box) 138 | 139 | 140 | plt.ylabel('mBTC') 141 | plt.xlabel('Dates') 142 | xfmt = md.DateFormatter('%Y-%m-%d') 143 | ax.xaxis.set_major_formatter(xfmt) 144 | 145 | 146 | axarr[0].plot(datenums,balance_Val,marker='o',linestyle='-',color='blue',label='Balance') 147 | axarr[0].legend(loc='upper left') 148 | axarr[0].set_title('History Transactions') 149 | 150 | 151 | xfmt = md.DateFormatter('%Y-%m-%d') 152 | ax.xaxis.set_major_formatter(xfmt) 153 | axarr[1].plot(datenums,fee_val,marker='o',linestyle='-',color='red',label='Fee') 154 | axarr[1].plot(datenums,value_val,marker='o',linestyle='-',color='green',label='Value') 155 | 156 | 157 | 158 | 159 | axarr[1].legend(loc='upper left') 160 | # plt.annotate('unknown transaction = %d \n pending transactions = %d' %(unknown_trans,pending_trans),xy=(0.7,0.05),xycoords='axes fraction',size=12) 161 | plt.show() 162 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # python setup.py sdist --format=zip,gztar 4 | 5 | from setuptools import setup 6 | import os 7 | import sys 8 | import platform 9 | import imp 10 | del os.link 11 | 12 | #os.system("pyrcc4 icons.qrc -o gui/qt/icons_rc.py") 13 | 14 | version = imp.load_source('version', 'lib/version.py') 15 | util = imp.load_source('util', 'lib/util.py') 16 | 17 | if sys.version_info[:3] < (2, 6, 0): 18 | sys.exit("Error: Encompass requires Python version >= 2.6.0...") 19 | usr_share = util.usr_share_dir() 20 | # presumes that user is competent if installing with additional options 21 | 22 | if (len(sys.argv) == 1 and (sys.argv[1] == "install")): 23 | usr_share = util.usr_share_dir() 24 | if not os.access(usr_share, os.W_OK): 25 | try: 26 | os.mkdir(usr_share) 27 | except: 28 | sys.exit("Error: cannot write to %s.\nIf you do not have root permissions, you may install Encompass in a virtualenv.\nAlso, please note that you can run Encompass without installing it on your system."%usr_share) 29 | 30 | data_files = [] 31 | if (len(sys.argv) > 1 and (sys.argv[1] == "sdist")) or (platform.system() != 'Windows' and platform.system() != 'Darwin'): 32 | print "Including all files" 33 | data_files += [ 34 | (os.path.join(usr_share, 'applications/'), ['encompass.desktop']), 35 | (os.path.join(usr_share, 'app-install', 'icons/'), ['icons/encompass.png']) 36 | ] 37 | if not os.path.exists('locale'): 38 | os.mkdir('locale') 39 | for lang in os.listdir('locale'): 40 | if os.path.exists('locale/%s/LC_MESSAGES/electrum.mo' % lang): 41 | data_files.append((os.path.join(usr_share, 'locale/%s/LC_MESSAGES' % lang), ['locale/%s/LC_MESSAGES/electrum.mo' % lang])) 42 | 43 | appdata_dir = os.path.join(usr_share, "encompass") 44 | 45 | data_files += [ 46 | (appdata_dir, ["data/README"]), 47 | (os.path.join(appdata_dir, "cleanlook"), [ 48 | "data/cleanlook/name.cfg", 49 | "data/cleanlook/style.css" 50 | ]), 51 | (os.path.join(appdata_dir, "sahara"), [ 52 | "data/sahara/name.cfg", 53 | "data/sahara/style.css" 54 | ]), 55 | (os.path.join(appdata_dir, "dark"), [ 56 | "data/dark/name.cfg", 57 | "data/dark/style.css" 58 | ]) 59 | ] 60 | 61 | for lang in os.listdir('data/wordlist'): 62 | data_files.append((os.path.join(appdata_dir, 'wordlist'), ['data/wordlist/%s' % lang])) 63 | 64 | 65 | setup( 66 | name="Encompass", 67 | version=version.ELECTRUM_VERSION, 68 | install_requires=[ 69 | 'slowaes==0.1a1', 70 | 'ecdsa==0.13', 71 | 'pbkdf2==1.3', 72 | 'requests==2.5.1', 73 | 'pyasn1-modules==0.0.5', 74 | 'pyasn1==0.1.7', 75 | 'qrcode==5.1', 76 | 'SocksiPy-branch==1.01', 77 | 'protobuf==2.5.0', 78 | 'tlslite==0.4.8', 79 | 'dnspython', 80 | 'ltc_scrypt==1.0', 81 | 'darkcoin_hash==1.1', 82 | 'trezor==0.6.3' 83 | ], 84 | dependency_links=[ 85 | "git+https://github.com/guruvan/darkcoin_hash#egg=darkcoin_hash" 86 | "git+https://github.com/mazaclub/python-trezor#egg=trezor" 87 | ], 88 | package_dir={ 89 | 'chainkey': 'lib', 90 | 'chainkey_gui': 'gui', 91 | 'chainkey_plugins': 'plugins', 92 | }, 93 | scripts=['encompass'], 94 | data_files=data_files, 95 | py_modules=[ 96 | 'chainkey.account', 97 | 'chainkey.bitcoin', 98 | 'chainkey.blockchain', 99 | 'chainkey.bmp', 100 | 'chainkey.chainparams', 101 | 'chainkey.commands', 102 | 'chainkey.daemon', 103 | 'chainkey.i18n', 104 | 'chainkey.interface', 105 | 'chainkey.mnemonic', 106 | 'chainkey.msqr', 107 | 'chainkey.network', 108 | 'chainkey.network_proxy', 109 | 'chainkey.old_mnemonic', 110 | 'chainkey.paymentrequest', 111 | 'chainkey.paymentrequest_pb2', 112 | 'chainkey.plugins', 113 | 'chainkey.qrscanner', 114 | 'chainkey.simple_config', 115 | 'chainkey.synchronizer', 116 | 'chainkey.transaction', 117 | 'chainkey.util', 118 | 'chainkey.verifier', 119 | 'chainkey.version', 120 | 'chainkey.wallet', 121 | 'chainkey.x509', 122 | 'chainkey.chains.__init__', 123 | 'chainkey.chains.bitcoin', 124 | 'chainkey.chains.cryptocur', 125 | 'chainkey.chains.mazacoin', 126 | 'chainkey.chains.scrypt', 127 | 'chainkey.chains.litecoin', 128 | 'chainkey.chains.viacoin', 129 | 'chainkey.chains.dash', 130 | 'chainkey_gui.gtk', 131 | 'chainkey_gui.qt.__init__', 132 | 'chainkey_gui.qt.amountedit', 133 | 'chainkey_gui.qt.console', 134 | 'chainkey_gui.qt.history_widget', 135 | 'chainkey_gui.qt.icons_rc', 136 | 'chainkey_gui.qt.installwizard', 137 | 'chainkey_gui.qt.lite_window', 138 | 'chainkey_gui.qt.main_window', 139 | 'chainkey_gui.qt.network_dialog', 140 | 'chainkey_gui.qt.password_dialog', 141 | 'chainkey_gui.qt.paytoedit', 142 | 'chainkey_gui.qt.qrcodewidget', 143 | 'chainkey_gui.qt.qrtextedit', 144 | 'chainkey_gui.qt.receiving_widget', 145 | 'chainkey_gui.qt.seed_dialog', 146 | 'chainkey_gui.qt.transaction_dialog', 147 | 'chainkey_gui.qt.util', 148 | 'chainkey_gui.qt.version_getter', 149 | 'chainkey_gui.stdio', 150 | 'chainkey_gui.text', 151 | 'chainkey_plugins.btchipwallet', 152 | 'chainkey_plugins.coinbase_buyback', 153 | 'chainkey_plugins.cosigner_pool', 154 | 'chainkey_plugins.exchange_rate', 155 | 'chainkey_plugins.greenaddress_instant', 156 | 'chainkey_plugins.labels', 157 | 'chainkey_plugins.trezor', 158 | 'chainkey_plugins.virtualkeyboard', 159 | 'chainkey_plugins.plot', 160 | 161 | ], 162 | description="Lightweight Multi-Coin Wallet", 163 | author="Tyler Willis, Rob Nelson, mazaclub", 164 | author_email="encompass-security@maza.club", 165 | license="GNU GPLv3", 166 | url="https://maza.club/encompass", 167 | long_description="""Lightweight Multi-Coin Wallet for Electrum-supported coins.""" 168 | ) 169 | -------------------------------------------------------------------------------- /lib/tests/test_wallet.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | import tempfile 3 | import sys 4 | import unittest 5 | import os 6 | import json 7 | 8 | from StringIO import StringIO 9 | from lib.wallet import WalletStorage, NewWallet 10 | from lib import chainparams 11 | 12 | if chainparams.get_active_chain() is None: 13 | chainparams.set_active_chain('BTC') 14 | 15 | 16 | class FakeConfig(object): 17 | """A stub config file to be used in tests""" 18 | def __init__(self, path): 19 | self.path = path 20 | self.store = {} 21 | 22 | def set(self, key, value): 23 | self.store[key] = value 24 | 25 | def get(self, key, default=None): 26 | return self.store.get(key, default) 27 | 28 | def get_above_chain(self, key, default=None): 29 | return self.store.get(key, default) 30 | 31 | 32 | class FakeSynchronizer(object): 33 | 34 | def __init__(self): 35 | self.store = [] 36 | 37 | def add(self, address): 38 | self.store.append(address) 39 | 40 | 41 | class WalletTestCase(unittest.TestCase): 42 | 43 | def setUp(self): 44 | super(WalletTestCase, self).setUp() 45 | self.user_dir = tempfile.mkdtemp() 46 | 47 | self.fake_config = FakeConfig(self.user_dir) 48 | 49 | self._saved_stdout = sys.stdout 50 | self._stdout_buffer = StringIO() 51 | sys.stdout = self._stdout_buffer 52 | 53 | def tearDown(self): 54 | super(WalletTestCase, self).tearDown() 55 | shutil.rmtree(self.user_dir) 56 | # Restore the "real" stdout 57 | sys.stdout = self._saved_stdout 58 | 59 | 60 | class TestWalletStorage(WalletTestCase): 61 | 62 | def test_init_wallet_default_path(self): 63 | storage = WalletStorage(self.fake_config) 64 | expected = os.path.join(self.user_dir, "wallets", "default_wallet") 65 | self.assertEqual(expected, storage.path) 66 | 67 | def test_init_wallet_explicit_path(self): 68 | path = os.path.join(self.user_dir, "somewallet") 69 | self.fake_config.set("wallet_path", path) 70 | 71 | storage = WalletStorage(self.fake_config) 72 | self.assertEqual(path, storage.path) 73 | 74 | def test_init_wallet_default_wallet_path(self): 75 | path = os.path.join(self.user_dir, "somewallet") 76 | self.fake_config.set("default_wallet_path", path) 77 | 78 | storage = WalletStorage(self.fake_config) 79 | self.assertEqual(path, storage.path) 80 | 81 | def test_read_dictionnary_from_file(self): 82 | path = os.path.join(self.user_dir, "somewallet") 83 | self.fake_config.set("wallet_path", path) 84 | 85 | some_dict = {"a":"b", "c":"d"} 86 | contents = repr(some_dict) 87 | with open(path, "w") as f: 88 | contents = f.write(contents) 89 | 90 | storage = WalletStorage(self.fake_config) 91 | self.assertEqual("b", storage.get_above_chain("a")) 92 | self.assertEqual("d", storage.get_above_chain("c")) 93 | 94 | def test_write_dictionnary_to_file(self): 95 | path = os.path.join(self.user_dir, "somewallet") 96 | self.fake_config.set("wallet_path", path) 97 | 98 | storage = WalletStorage(self.fake_config) 99 | 100 | some_dict = {"a":"b", "c":"d"} 101 | storage.data = some_dict 102 | 103 | storage.write() 104 | 105 | contents = "" 106 | with open(path, "r") as f: 107 | contents = f.read() 108 | self.assertEqual(some_dict, json.loads(contents)) 109 | 110 | 111 | class TestNewWallet(WalletTestCase): 112 | 113 | seed_text = "travel nowhere air position hill peace suffer parent beautiful rise blood power home crumble teach" 114 | password = "secret" 115 | 116 | first_account_name = "account1" 117 | 118 | import_private_key = "L52XzL2cMkHxqxBXRyEpnPQZGUs3uKiL3R11XbAdHigRzDozKZeW" 119 | import_key_address = "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma" 120 | 121 | def setUp(self): 122 | super(TestNewWallet, self).setUp() 123 | self.storage = WalletStorage(self.fake_config) 124 | self.wallet = NewWallet(self.storage) 125 | # This cannot be constructed by electrum at random, it should be safe 126 | # from eventual collisions. 127 | self.wallet.add_seed(self.seed_text, self.password) 128 | self.wallet.create_master_keys(self.password) 129 | self.wallet.create_main_account(self.password) 130 | 131 | def test_wallet_with_seed_is_not_watching_only(self): 132 | self.assertFalse(self.wallet.is_watching_only()) 133 | 134 | def test_wallet_without_seed_is_watching_only(self): 135 | # We need a new storage , since the default storage was already seeded 136 | # in setUp() 137 | new_dir = tempfile.mkdtemp() 138 | config = FakeConfig(new_dir) 139 | storage = WalletStorage(config) 140 | wallet = NewWallet(storage) 141 | self.assertTrue(wallet.is_watching_only()) 142 | shutil.rmtree(new_dir) # Don't leave useless stuff in /tmp 143 | 144 | def test_new_wallet_is_deterministic(self): 145 | self.assertTrue(self.wallet.is_deterministic()) 146 | 147 | def test_get_seed_returns_correct_seed(self): 148 | self.assertEqual(self.wallet.get_seed(self.password), self.seed_text) 149 | 150 | 151 | def test_key_import(self): 152 | # Wallets have no imported keys by default. 153 | self.assertFalse(self.wallet.has_imported_keys()) 154 | 155 | # Importing a key works. 156 | self.wallet.import_key(self.import_private_key, "") 157 | self.assertEqual(1, len(self.wallet.addresses())) 158 | self.assertIn(self.import_key_address, self.wallet.addresses()) 159 | 160 | self.assertTrue(self.wallet.has_imported_keys()) 161 | 162 | # Deleting the key works. 163 | self.wallet.delete_imported_key(self.import_key_address) 164 | self.assertFalse(self.wallet.has_imported_keys()) 165 | self.assertEqual(0, len(self.wallet.addresses())) 166 | self.assertNotIn(self.import_key_address, self.wallet.addresses()) 167 | 168 | def test_update_password(self): 169 | new_password = "secret2" 170 | self.wallet.update_password(self.password, new_password) 171 | self.wallet.get_seed(new_password) 172 | -------------------------------------------------------------------------------- /lib/mnemonic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Electrum - lightweight Bitcoin client 4 | # Copyright (C) 2014 Thomas Voegtlin 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import os 20 | import hmac 21 | import math 22 | import hashlib 23 | import unicodedata 24 | import string 25 | 26 | import ecdsa 27 | import pbkdf2 28 | 29 | import util 30 | from util import print_error 31 | from bitcoin import is_old_seed, is_new_seed 32 | import version 33 | import i18n 34 | 35 | # http://www.asahi-net.or.jp/~ax2s-kmtn/ref/unicode/e_asia.html 36 | CJK_INTERVALS = [ 37 | (0x4E00, 0x9FFF, 'CJK Unified Ideographs'), 38 | (0x3400, 0x4DBF, 'CJK Unified Ideographs Extension A'), 39 | (0x20000, 0x2A6DF, 'CJK Unified Ideographs Extension B'), 40 | (0x2A700, 0x2B73F, 'CJK Unified Ideographs Extension C'), 41 | (0x2B740, 0x2B81F, 'CJK Unified Ideographs Extension D'), 42 | (0xF900, 0xFAFF, 'CJK Compatibility Ideographs'), 43 | (0x2F800, 0x2FA1D, 'CJK Compatibility Ideographs Supplement'), 44 | (0x3190, 0x319F , 'Kanbun'), 45 | (0x2E80, 0x2EFF, 'CJK Radicals Supplement'), 46 | (0x2F00, 0x2FDF, 'CJK Radicals'), 47 | (0x31C0, 0x31EF, 'CJK Strokes'), 48 | (0x2FF0, 0x2FFF, 'Ideographic Description Characters'), 49 | (0xE0100, 0xE01EF, 'Variation Selectors Supplement'), 50 | (0x3100, 0x312F, 'Bopomofo'), 51 | (0x31A0, 0x31BF, 'Bopomofo Extended'), 52 | (0xFF00, 0xFFEF, 'Halfwidth and Fullwidth Forms'), 53 | (0x3040, 0x309F, 'Hiragana'), 54 | (0x30A0, 0x30FF, 'Katakana'), 55 | (0x31F0, 0x31FF, 'Katakana Phonetic Extensions'), 56 | (0x1B000, 0x1B0FF, 'Kana Supplement'), 57 | (0xAC00, 0xD7AF, 'Hangul Syllables'), 58 | (0x1100, 0x11FF, 'Hangul Jamo'), 59 | (0xA960, 0xA97F, 'Hangul Jamo Extended A'), 60 | (0xD7B0, 0xD7FF, 'Hangul Jamo Extended B'), 61 | (0x3130, 0x318F, 'Hangul Compatibility Jamo'), 62 | (0xA4D0, 0xA4FF, 'Lisu'), 63 | (0x16F00, 0x16F9F, 'Miao'), 64 | (0xA000, 0xA48F, 'Yi Syllables'), 65 | (0xA490, 0xA4CF, 'Yi Radicals'), 66 | ] 67 | 68 | def is_CJK(c): 69 | n = ord(c) 70 | for imin,imax,name in CJK_INTERVALS: 71 | if n>=imin and n<=imax: return True 72 | return False 73 | 74 | 75 | def prepare_seed(seed): 76 | # normalize 77 | seed = unicodedata.normalize('NFKD', unicode(seed)) 78 | # lower 79 | seed = seed.lower() 80 | # remove accents 81 | seed = u''.join([c for c in seed if not unicodedata.combining(c)]) 82 | # normalize whitespaces 83 | seed = u' '.join(seed.split()) 84 | # remove whitespaces between CJK 85 | seed = u''.join([seed[i] for i in range(len(seed)) if not (seed[i] in string.whitespace and is_CJK(seed[i-1]) and is_CJK(seed[i+1]))]) 86 | return seed 87 | 88 | 89 | filenames = { 90 | 'en':'english.txt', 91 | 'es':'spanish.txt', 92 | 'ja':'japanese.txt', 93 | 'pt':'portuguese.txt', 94 | } 95 | 96 | 97 | 98 | class Mnemonic(object): 99 | # Seed derivation no longer follows BIP39 100 | # Mnemonic phrase uses a hash based checksum, instead of a wordlist-dependent checksum 101 | 102 | def __init__(self, lang=None): 103 | if lang in [None, '']: 104 | lang = i18n.language.info().get('language', 'en') 105 | print_error('language', lang) 106 | filename = filenames.get(lang[0:2], 'english.txt') 107 | path = os.path.join(util.data_dir(), 'wordlist', filename) 108 | s = open(path,'r').read().strip() 109 | s = unicodedata.normalize('NFKD', s.decode('utf8')) 110 | lines = s.split('\n') 111 | self.wordlist = [] 112 | for line in lines: 113 | line = line.split('#')[0] 114 | line = line.strip(' \r') 115 | assert ' ' not in line 116 | if line: 117 | self.wordlist.append(line) 118 | print_error("wordlist has %d words"%len(self.wordlist)) 119 | 120 | @classmethod 121 | def mnemonic_to_seed(self, mnemonic, passphrase): 122 | PBKDF2_ROUNDS = 2048 123 | mnemonic = prepare_seed(mnemonic) 124 | return pbkdf2.PBKDF2(mnemonic, 'mnemonic' + passphrase, iterations = PBKDF2_ROUNDS, macmodule = hmac, digestmodule = hashlib.sha512).read(64) 125 | 126 | def mnemonic_encode(self, i): 127 | n = len(self.wordlist) 128 | words = [] 129 | while i: 130 | x = i%n 131 | i = i/n 132 | words.append(self.wordlist[x]) 133 | return ' '.join(words) 134 | 135 | def mnemonic_decode(self, seed): 136 | n = len(self.wordlist) 137 | words = seed.split() 138 | i = 0 139 | while words: 140 | w = words.pop() 141 | k = self.wordlist.index(w) 142 | i = i*n + k 143 | return i 144 | 145 | def check_seed(self, seed, custom_entropy): 146 | assert is_new_seed(seed) 147 | i = self.mnemonic_decode(seed) 148 | return i % custom_entropy == 0 149 | 150 | def make_seed(self, num_bits=128, prefix=version.SEED_BIP44, custom_entropy=1): 151 | n = int(math.ceil(math.log(custom_entropy,2))) 152 | # bits of entropy used by the prefix 153 | k = len(prefix)*4 154 | # we add at least 16 bits 155 | n_added = max(16, k + num_bits - n) 156 | print_error("make_seed", prefix, "adding %d bits"%n_added) 157 | my_entropy = ecdsa.util.randrange( pow(2, n_added) ) 158 | nonce = 0 159 | while True: 160 | nonce += 1 161 | i = custom_entropy * (my_entropy + nonce) 162 | seed = self.mnemonic_encode(i) 163 | assert i == self.mnemonic_decode(seed) 164 | if is_old_seed(seed): 165 | continue 166 | if is_new_seed(seed, prefix): 167 | break 168 | print_error('%d words'%len(seed.split())) 169 | return seed 170 | --------------------------------------------------------------------------------