mirror of
https://github.com/jwinterm/lightWallet.git
synced 2026-10-17 05:11:25 +02:00
Initial commit
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
# lightWallet Kivy GUI
|
||||
This is a GUI frontend that runs on top of bitmonerod and simplewallet (in RPC mode). It is designed to work with a remote bitmonerod node, so that it can function as a lightweight wallet for most users. **This program is an early beta version, and although I don't think there is really any way to screw up your wallet, please exercise some modicum of caution.**
|
||||
|
||||
## Installation
|
||||
### Windows, Linux, and Mac
|
||||
The requirements for running the program are: Python 2.7, Kivy 1.8, and pygame 1.9.1. If you have these requirements, then you just need to add your binary (simplewallet.exe) and optionally wallet files to your cryptonoteRPCwalletGUI folder, or unzip the cryptonoteRPCwalletGUI contents into the folder where you currently have your binaries and wallet files. For the time being they have to be in the same local directory.
|
||||
|
||||
Currently there are no binaries available, but the plan is to compile an exe for Windows, andfrom there it should be easy to create binaries for linux.
|
||||
|
||||
## Running
|
||||
It should be OK to launch the program with an instance of bitmonerod and/or simplewallet running.
|
||||
|
||||
On the initial run, it will prompt you to create a new wallet or to import one by typing/copying in the path of the keys file. This will create a folder in the local directory where the new/imported wallet data is stored, and a file called CONFIG.file that let's lightWallet know which account is currently the default one being used.
|
||||
|
||||
## Future Work
|
||||
There are several features I'd like to implement, the most important of which is probably tab or file keeping a record of all incoming and outgoing transactions. This is a really key feature that should probably be a part of any wallet, but I'm still having some trouble with the gui here, so it is delayed for the time being.
|
||||
|
||||
Another thing I want to change is using argparse rather than argv to parse command line arguments. This should make the program more robust (less crashy) and offer the user additional help at the command line. I probably want to clean up the interface and prettify it a bit more too. I'm open to suggestions too, so please open an issue or email me if you have any ideas, complaints, etc.
|
||||
@@ -0,0 +1,7 @@
|
||||
import argparse
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.parse_args()
|
||||
|
||||
print parser.parse_args()
|
||||
@@ -0,0 +1,49 @@
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
|
||||
serverURL = 'http://localhost:19091/json_rpc'
|
||||
headers = {'content-type': 'application/json'}
|
||||
payload1 = json.dumps({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getbalance",
|
||||
"params": {}
|
||||
})
|
||||
payload2 = json.dumps({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getaddress",
|
||||
"params": {}
|
||||
})
|
||||
|
||||
def balancecheck(jobqueue, resultsqueue):
|
||||
"""function to make rpc call to simplewallet to get current balance"""
|
||||
kivysignal = True
|
||||
while kivysignal:
|
||||
time.sleep(2)
|
||||
walletrunning, kivysignal = jobqueue.get()
|
||||
if walletrunning:
|
||||
#print 'attempting rpc call'
|
||||
try:
|
||||
#Make rpc call
|
||||
resp1 = requests.get(serverURL, headers=headers, data=payload1)
|
||||
output1 = json.loads(resp1.text)
|
||||
|
||||
#Parse json data to get balance info
|
||||
rawbalance = str(output1[u'result'][u'balance']/1e12)
|
||||
rawunlockedbalance = str(output1[u'result'][u'unlocked_balance']/1e12)
|
||||
|
||||
#Format data for kivy
|
||||
balance = '[color=00ff00]'+rawbalance+'[/color]'
|
||||
unlockedbalance = '[color=00ff00]'+rawunlockedbalance+'[/color]'
|
||||
|
||||
resp2 = requests.get(serverURL, headers=headers, data=payload2)
|
||||
output2 = json.loads(resp2.text)
|
||||
address = str(output2[u'result'][u'address'])
|
||||
|
||||
except:
|
||||
#Return out of sync if bitmonerod is not ready
|
||||
balance = '[color=ff0000]out of sync[/color]'
|
||||
unlockedbalance = '[color=ff0000]out of sync[/color]'
|
||||
address = '[color=ff0000]out of sync[/color]'
|
||||
|
||||
resultsqueue.put((balance, unlockedbalance, address))
|
||||
@@ -0,0 +1,16 @@
|
||||
from subprocess import PIPE, Popen
|
||||
from threading import Thread
|
||||
from Queue import Queue, Empty
|
||||
|
||||
def bitmonerodloader():
|
||||
"""Start bitmonerod and/or simplewallet and collect wallet name and address"""
|
||||
p = Popen(
|
||||
# ["bitmonerod.exe", "--set_log", "0"],
|
||||
["bitmonerod.exe", "--set_log", "0"],
|
||||
stdout=PIPE,
|
||||
stdin=PIPE,
|
||||
bufsize=1,
|
||||
close_fds=ON_POSIX)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import requests
|
||||
import json
|
||||
|
||||
serverURL = 'http://localhost:8082/json_rpc'
|
||||
|
||||
|
||||
def CheckBalanceSimplewallet():
|
||||
"""function to make rpc call to simplewallet to get current balance"""
|
||||
payload = json.dumps({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getbalance",
|
||||
"params": {}
|
||||
})
|
||||
print 'Attempting {0} RPC call'.format(CheckBalanceSimplewallet.__name__)
|
||||
try:
|
||||
#Make rpc call
|
||||
headers = {'content-type': 'application/json'}
|
||||
resp = requests.get(serverURL, headers=headers, data=payload)
|
||||
output = json.loads(resp.text)
|
||||
|
||||
#Parse json data to get balance info
|
||||
balance = str(output[u'result'][u'balance']/1e12)
|
||||
unlockedbalance = str(output[u'result'][u'unlocked_balance']/1e12)
|
||||
|
||||
return output, balance, unlockedbalance
|
||||
|
||||
|
||||
except:
|
||||
#Return out of sync if bitmonerod is not ready
|
||||
message = "Can't connect to simplewallet"
|
||||
return message, message, message
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print CheckBalanceSimplewallet()
|
||||
@@ -0,0 +1,43 @@
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
import datetime
|
||||
|
||||
|
||||
# Set server for RPC call to bitmonerod
|
||||
default_URL = 'http://xmr1.coolmining.club:5012/json_rpc'
|
||||
# Headers, because headers
|
||||
headers = {'content-type': 'application/json'}
|
||||
# Data to give to bitmonerod to check last block info
|
||||
payload = json.dumps({
|
||||
"jsonrpc": "2.0",
|
||||
"id": "test",
|
||||
"method": "getlastblockheader"
|
||||
})
|
||||
|
||||
|
||||
def CheckLastBlock(serverURL=default_URL):
|
||||
"""Try and get last block info and return formatted text"""
|
||||
# print('Attempting {0} RPC call'.format(CheckLastBlock.__name__))
|
||||
try:
|
||||
resp = requests.get(serverURL, headers=headers, data=payload)
|
||||
output = json.loads(resp.text)
|
||||
# print(output)
|
||||
height = output[u'result'][u'block_header'][u'height']
|
||||
reward = output[u'result'][u'block_header'][u'reward']
|
||||
linuxblocktime = output[u'result'][u'block_header'][u'timestamp']
|
||||
linuxtimenow = time.time()
|
||||
timesince = linuxtimenow - linuxblocktime
|
||||
localtime = datetime.datetime.fromtimestamp(int(linuxblocktime
|
||||
)).strftime('%Y-%m-%d %H:%M:%S')
|
||||
return height, reward, timesince, localtime
|
||||
|
||||
|
||||
except:
|
||||
#Return out of sync if bitmonerod is not ready
|
||||
message = "Can't connect to bitmonerod"
|
||||
return message, message, message, message
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
CheckLastBlock()
|
||||
@@ -0,0 +1,22 @@
|
||||
import requests
|
||||
import json
|
||||
|
||||
serverURL = 'http://localhost:8082/json_rpc'
|
||||
|
||||
payload = json.dumps({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "store",
|
||||
"params": {}
|
||||
})
|
||||
|
||||
|
||||
def checkwalletrpccall():
|
||||
headers = {'content-type': 'application/json'}
|
||||
resp = requests.get(serverURL, headers=headers, data=payload)
|
||||
output = json.loads(resp.text)
|
||||
print output
|
||||
|
||||
# return output[u'result'][u'balance'], output[u'result'][u'unlocked_balance']
|
||||
|
||||
if __name__ == "__main__":
|
||||
checkwallet()
|
||||
@@ -0,0 +1,16 @@
|
||||
import subprocess
|
||||
from sys import platform
|
||||
|
||||
|
||||
def cpuminerloader(minerurl, user, pw, threads):
|
||||
"""Start cpuminer"""
|
||||
print "Start miner button pressed..."
|
||||
#Start cpuminer daemon if not running
|
||||
if platform == 'win32':
|
||||
daemonproc = subprocess.Popen("start minerd.exe -a cryptonight -o {0} -u {1} -p {2} -t {3}".format(
|
||||
minerurl, user, pw, threads), shell=True)
|
||||
elif platform == 'linux' or platform == 'linux2' or platform == 'linux32':
|
||||
print "linux!"
|
||||
daemonproc = subprocess.Popen('xterm -bg black -e "./minerd -a cryptonight -o {0} -u {1} -p {2} -t {3}"'.format(
|
||||
minerurl, user, pw, threads), shell=True)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/python
|
||||
from sys import platform
|
||||
import subprocess as sub
|
||||
import time
|
||||
from lib.checklastblock import CheckLastBlock
|
||||
|
||||
|
||||
def runningcheck():
|
||||
"""Function to check if daemon is running"""
|
||||
daemonrunning = False
|
||||
if platform == 'win32':
|
||||
import wmi
|
||||
wmi = wmi.WMI ()
|
||||
for process in wmi.Win32_Process(name='bitmonerod.exe'):
|
||||
#print process.ProcessId, process.Name
|
||||
if process.Name:
|
||||
daemonrunning = True
|
||||
|
||||
elif platform == 'linux' or platform == 'linux2' or platform == 'linux32':
|
||||
p = sub.Popen("ps -A | grep bitmonerod", shell=True, stdout=sub.PIPE, stderr=sub.PIPE)
|
||||
output, errors = p.communicate()
|
||||
if output:
|
||||
daemonrunning = True
|
||||
return daemonrunning
|
||||
|
||||
def daemoncheck(queue):
|
||||
"""Check if bitmonerod daemon is running and return values to kivy"""
|
||||
print "Starting checkdaemon thread on: {0}".format(platform)
|
||||
|
||||
while True:
|
||||
daemonrunning = runningcheck()
|
||||
if daemonrunning:
|
||||
try:
|
||||
checklastblockoutput = CheckLastBlock()
|
||||
|
||||
except:
|
||||
checklastblockoutput = 'error'
|
||||
else:
|
||||
checklastblockoutput = 'daemon not running'
|
||||
queue.put((daemonrunning, checklastblockoutput))
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
daemoncheck()
|
||||
@@ -0,0 +1,29 @@
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
|
||||
serverURL = 'http://localhost:19091/json_rpc'
|
||||
|
||||
headers = {'content-type': 'application/json'}
|
||||
|
||||
payload = json.dumps({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "incoming_transfers",
|
||||
"params": {"transfer_type": "all"}
|
||||
})
|
||||
|
||||
|
||||
def getTransfers():
|
||||
resp = requests.get(serverURL, headers=headers, data=payload)
|
||||
try:
|
||||
output = json.loads(resp.text)
|
||||
# print output
|
||||
except:
|
||||
# print "Waiting for bitmonerod client to sync with network..."
|
||||
output = "Waiting for bitmonerod client to sync with network..."
|
||||
|
||||
print output
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
getTransfers()
|
||||
@@ -0,0 +1,58 @@
|
||||
# !/usr/bin/python
|
||||
from sys import platform
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
|
||||
def runningcheck():
|
||||
"""Function to check if daemon is running"""
|
||||
daemonrunning, walletrunning, minerrunning = False, False, False
|
||||
if platform == 'win32':
|
||||
import wmi
|
||||
|
||||
wmi = wmi.WMI()
|
||||
for process in wmi.Win32_Process():
|
||||
# print process.ProcessId, process.Name
|
||||
if process.Name == 'bitmonerod.exe':
|
||||
daemonrunning = True
|
||||
# print 'daemon'
|
||||
if process.Name == 'simplewallet.exe':
|
||||
walletrunning = True
|
||||
# print 'wallet'
|
||||
if process.Name == 'minerd.exe':
|
||||
minerrunning = True
|
||||
# print 'miner'
|
||||
elif platform == 'linux' or platform == 'linux2' or platform == 'darwin':
|
||||
p = subprocess.Popen("ps -A", shell=True, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
output, errors = p.communicate()
|
||||
if 'bitmonerod' in output:
|
||||
daemonrunning = True
|
||||
if 'simplewallet' in output:
|
||||
walletrunning = True
|
||||
if 'minerd' in output:
|
||||
minerrunning = True
|
||||
return daemonrunning, walletrunning, minerrunning
|
||||
|
||||
|
||||
def isrunning(jobqueue, resultsqueue):
|
||||
"""Check if bitmonerod daemon is running and return values to kivy"""
|
||||
print "Starting checkdaemon thread on: {0}".format(platform)
|
||||
kivysignal = True
|
||||
while kivysignal:
|
||||
try:
|
||||
daemonrunning, walletrunning, minerrunning = runningcheck()
|
||||
if daemonrunning:
|
||||
daemoncheckerlabeltext = "[color=00ff00]It appears the bitmonerod daemon is running.[/color]"
|
||||
else:
|
||||
daemoncheckerlabeltext = "[color=ff0000]Click the [b]Start network daemon[/b] button to load bitmonerod.[/color]"
|
||||
if walletrunning:
|
||||
walletcheckerlabeltext = "[color=00ff00]It appears the simplewallet daemon is running.[/color]"
|
||||
else:
|
||||
walletcheckerlabeltext = "[color=00ff00]Click the [b]Initialize wallet file[/b] button to load simplewallet.[/color]"
|
||||
resultsqueue.put((daemonrunning, daemoncheckerlabeltext, walletrunning,
|
||||
walletcheckerlabeltext, minerrunning))
|
||||
except:
|
||||
pass
|
||||
time.sleep(0.1)
|
||||
kivysignal = jobqueue.get(kivysignal)
|
||||
@@ -0,0 +1,22 @@
|
||||
import os
|
||||
import time
|
||||
|
||||
def namecheck(jobqueue, resultsqueue):
|
||||
kivysignal = True
|
||||
while kivysignal:
|
||||
try:
|
||||
walletname, kivysignal = jobqueue.get()
|
||||
# print walletname
|
||||
if walletname == "No filename":
|
||||
message = "Please input a wallet file name..."
|
||||
isname = None
|
||||
elif os.path.isfile(walletname):
|
||||
message = "Wallet file {0} exists in local directory.\nPlease press [b]Initialize wallet file[/b] to [color=00ff00]load wallet file[/color].".format(walletname)
|
||||
isname = True
|
||||
if not os.path.isfile(walletname):
|
||||
message = "Wallet file {0} does not exist in your local directory.\nPlease press [b]Initialize wallet file[/b] to [color=00ff00]generate new wallet file[/color].".format(walletname)
|
||||
isname = False
|
||||
resultsqueue.put((isname, message))
|
||||
except:
|
||||
pass
|
||||
time.sleep(0.1)
|
||||
@@ -0,0 +1,26 @@
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
|
||||
serverURL = 'http://localhost:18081/save_bc'
|
||||
|
||||
headers = {'content-type': 'application/json'}
|
||||
|
||||
# payload = json.dumps({
|
||||
# "jsonrpc": "2.0",
|
||||
# "id": "test",
|
||||
# "method": "save_bc"
|
||||
# })
|
||||
|
||||
|
||||
def save_bc():
|
||||
#resp = requests.get(serverURL, headers=headers, data=payload)
|
||||
resp = requests.get(serverURL)
|
||||
# try:
|
||||
# output = json.loads(resp.text)
|
||||
# print output
|
||||
# except:
|
||||
# print "Waiting for bitmonerod client to sync with network..."
|
||||
# output = "Waiting for bitmonerod client to sync with network..."
|
||||
|
||||
print resp.text
|
||||
@@ -0,0 +1,25 @@
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
|
||||
serverURL = 'http://localhost:19091/json_rpc'
|
||||
|
||||
headers = {'content-type': 'application/json'}
|
||||
|
||||
payload = json.dumps({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "store",
|
||||
"params": {}
|
||||
})
|
||||
|
||||
|
||||
def storeWallet():
|
||||
resp = requests.get(serverURL, headers=headers, data=payload)
|
||||
try:
|
||||
output = json.loads(resp.text)
|
||||
# print output
|
||||
except:
|
||||
# print "Waiting for bitmonerod client to sync with network..."
|
||||
output = "Waiting for bitmonerod client to sync with network..."
|
||||
|
||||
# print output
|
||||
@@ -0,0 +1,62 @@
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
from sys import platform
|
||||
|
||||
|
||||
def simplewalletloader(walletname, walletpw, isname):
|
||||
"""Function to create and/or open wallet in simplewallet rpc mode"""
|
||||
# Launch simplewallet in rpc mode if wallet file exists
|
||||
if isname == True:
|
||||
# os.remove(walletname)
|
||||
print "***Opening ___" + walletname + "___ wallet file rpc interface***"
|
||||
if platform == 'win32':
|
||||
subprocess.Popen(
|
||||
"start simplewallet.exe --wallet-file {0} --password {1} --rpc-bind-port 19091 --set_log 0\r\nnpause".format(
|
||||
walletname, walletpw), shell=True)
|
||||
elif platform == 'linux' or platform == 'linux2' or platform == 'darwin':
|
||||
subprocess.Popen(
|
||||
'xterm -bg black -hold -e "./simplewallet --wallet-file {0} --password {1} --rpc-bind-port 19091"'.format(
|
||||
walletname, walletpw))
|
||||
|
||||
# Generate and then launch if wallet file doesn't exist
|
||||
elif isname == False:
|
||||
print "Generating wallet file " + walletname
|
||||
if platform == 'win32':
|
||||
walletgen = subprocess.Popen(
|
||||
"simplewallet.exe --generate-new-wallet {0} --password {1} --set_log 0".format(
|
||||
walletname, walletpw), shell=True, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
elif platform == 'linux' or platform == 'linux2' or platform == 'darwin':
|
||||
walletgen = subprocess.Popen(
|
||||
"./simplewallet --generate-new-wallet {0} --password {1} --set_log 0".format(
|
||||
walletname, walletpw), shell=True, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
print "Wallet gen'ed"
|
||||
time.sleep(5)
|
||||
#print walletgen.stdout.read()
|
||||
#print walletgen.communicate('exit')
|
||||
walletgen.terminate()
|
||||
if platform == 'win32':
|
||||
os.system("taskkill /im simplewallet.exe /f")
|
||||
elif platform == 'linux' or platform == 'linux2' or platform == 'darwin':
|
||||
p = subprocess.Popen("pgrep simplewallet", shell=True, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
output, errors = p.communicate()
|
||||
output = output.split('\n')
|
||||
for i in output:
|
||||
os.system("kill -9 {0}".format(i))
|
||||
# Launch simplewallet in rpc mode now that wallet file exists
|
||||
print "***Opening ___" + walletname + "___ wallet file rpc interface***"
|
||||
if platform == 'win32':
|
||||
subprocess.Popen(
|
||||
"start simplewallet --wallet-file {0} --password {1} --rpc-bind-port 19091 --set_log 0\r\nnpause".format(
|
||||
walletname, walletpw), shell=True)
|
||||
elif platform == 'linux' or platform == 'linux2' or platform == 'linux32':
|
||||
subprocess.Popen(
|
||||
'xterm -bg black -hold -e "./simplewallet --wallet-file {0} --password {1} --rpc-bind-port 19091 --set_log 0"'.format(
|
||||
walletname, walletpw), shell=True)
|
||||
|
||||
|
||||
elif isname == None:
|
||||
pass
|
||||
@@ -0,0 +1,64 @@
|
||||
import requests
|
||||
import json
|
||||
from ctypes import c_uint64
|
||||
|
||||
serverURL = 'http://localhost:19091/json_rpc'
|
||||
|
||||
|
||||
def transferfundsrpccall(amount, address, mixin, paymentid):
|
||||
"""function to transfer funds to a single address"""
|
||||
atomicamount = c_uint64(int((float(amount)*1e12)-1e6))
|
||||
address = str(address)
|
||||
mixin = int(mixin)
|
||||
paymentid = str(paymentid)
|
||||
mro_fee = c_uint64(int(1e11))
|
||||
if len(paymentid) > 1:
|
||||
payload = json.dumps({
|
||||
"jsonrpc":"2.0",
|
||||
"method":"transfer",
|
||||
"params":{
|
||||
"destinations":[
|
||||
{
|
||||
"amount":atomicamount.value,
|
||||
"address":address
|
||||
}
|
||||
],
|
||||
"fee":mro_fee.value,
|
||||
"mixin":mixin,
|
||||
"unlock_time":0,
|
||||
"payment_id":paymentid
|
||||
}
|
||||
})
|
||||
else:
|
||||
payload = json.dumps({
|
||||
"jsonrpc":"2.0",
|
||||
"method":"transfer",
|
||||
"params":{
|
||||
"destinations":[
|
||||
{
|
||||
"amount":atomicamount.value,
|
||||
"address":address
|
||||
}
|
||||
],
|
||||
"fee":mro_fee.value,
|
||||
"mixin":mixin,
|
||||
"unlock_time":0
|
||||
}
|
||||
})
|
||||
print payload
|
||||
|
||||
try:
|
||||
headers = {'content-type': 'application/json'}
|
||||
resp = requests.get(serverURL, headers=headers, data=payload)
|
||||
output = json.loads(resp.text)
|
||||
print output
|
||||
txid = output[u'result'][u'tx_hash']
|
||||
return txid
|
||||
|
||||
except:
|
||||
print "transfer error :0 !!!"
|
||||
return "error"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
transferfundsrpccall()
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
#:kivy 1.8.0
|
||||
|
||||
<RootWidget>:
|
||||
id: rootwidget
|
||||
# Tx history tab id items
|
||||
tx_list: tx_list
|
||||
# Transfer tab id items
|
||||
address_input_textinput: address_input_textinput
|
||||
amount_input_textinput: amount_input_textinput
|
||||
mixin_input_textinput: mixin_input_textinput
|
||||
paymentid_input_textinput: paymentid_input_textinput
|
||||
# Wallet account tab id items
|
||||
wallet_account_label: wallet_account_label
|
||||
wallet_address_label: wallet_address_label
|
||||
wallet_block_label: wallet_block_label
|
||||
unlocked_balance_label: unlocked_balance_label
|
||||
total_balance_label: total_balance_label
|
||||
calculated_balance_label: calculated_balance_label
|
||||
# Bitmonerod daemon tab id items
|
||||
daemon_server_textinput: daemon_server_textinput
|
||||
blockheight_label: blockheight_label
|
||||
last_reward_label: last_reward_label
|
||||
last_block_time_label: last_block_time_label
|
||||
time_since_last_label: time_since_last_label
|
||||
|
||||
AccordionItem:
|
||||
title: "Transaction history"
|
||||
ScrollView:
|
||||
size_hint: None, None
|
||||
GridLayout:
|
||||
cols: 1
|
||||
spacing: 7
|
||||
# size_hint_y: None
|
||||
id: tx_list
|
||||
|
||||
AccordionItem:
|
||||
title: "Send XMR"
|
||||
BoxLayout:
|
||||
padding: 30, 30, 30, 30
|
||||
orientation: 'vertical'
|
||||
Label:
|
||||
text: "Send to address:"
|
||||
size_hint_x: 0.2
|
||||
TextInput:
|
||||
id: address_input_textinput
|
||||
size_hint_x: 2
|
||||
font_size: 10
|
||||
multiline: False
|
||||
Label:
|
||||
text: "Amount MRO:"
|
||||
size_hint_x: 0.2
|
||||
TextInput:
|
||||
id: amount_input_textinput
|
||||
size_hint_x: 0.8
|
||||
font_size: 10
|
||||
multiline: False
|
||||
Label:
|
||||
text: "Mixin amount:\n(Please use 0 or >= 3)"
|
||||
size_hint_x: 0.2
|
||||
TextInput:
|
||||
id: mixin_input_textinput
|
||||
size_hint_x: 0.8
|
||||
font_size: 10
|
||||
multiline: False
|
||||
Label:
|
||||
text: "Payment ID:"
|
||||
size_hint_x: 0.2
|
||||
TextInput:
|
||||
id: paymentid_input_textinput
|
||||
size_hint_x: 1
|
||||
font_size: 10
|
||||
text: ""
|
||||
multiline: False
|
||||
Button:
|
||||
text: "Transfer funds"
|
||||
on_press: root.transferfunds()
|
||||
# on_press: root.storeformdata()
|
||||
font_size: 20
|
||||
|
||||
AccordionItem:
|
||||
title: "Simplewallet account"
|
||||
BoxLayout:
|
||||
orientation: 'vertical'
|
||||
padding: 30, 30, 30, 30
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
Label:
|
||||
text: "Account name: "
|
||||
MarkupLabel:
|
||||
id: wallet_account_label
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
Label:
|
||||
size_hint_x: 0.15
|
||||
text: "Address: "
|
||||
MarkupLabel:
|
||||
id: wallet_address_label
|
||||
size_hint_x: 0.9
|
||||
font_size: 9
|
||||
on_ref_press: root.selectAddress()
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
Label:
|
||||
text: "Blocks synced: "
|
||||
MarkupLabel:
|
||||
id: wallet_block_label
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
Label:
|
||||
text: "Unlocked balance: "
|
||||
MarkupLabel:
|
||||
id: unlocked_balance_label
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
Label:
|
||||
text: "Total balance: "
|
||||
MarkupLabel:
|
||||
id: total_balance_label
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
Label:
|
||||
text: "Calculated balance: "
|
||||
MarkupLabel:
|
||||
id: calculated_balance_label
|
||||
|
||||
AccordionItem:
|
||||
title: "Bitmonerod daemon"
|
||||
BoxLayout:
|
||||
orientation: 'vertical'
|
||||
padding: 30, 30, 30, 30
|
||||
Image:
|
||||
size_hint_y: 0.2
|
||||
source: 'logo.png'
|
||||
Label:
|
||||
size_hint_y: 0.05
|
||||
text: "A lightweight Monero GUI account manager"
|
||||
Label:
|
||||
size_hint_y: 0.1
|
||||
Label:
|
||||
text: "Daemon ip address (default is coolmining club)"
|
||||
size_hint_y: 0.05
|
||||
BoxLayout:
|
||||
size_hint_y: 0.15
|
||||
orientation: 'horizontal'
|
||||
TextInput:
|
||||
size_hint_x: 0.7
|
||||
id: daemon_server_textinput
|
||||
text: "http://xmr1.coolmining.club:5012"
|
||||
# text: "http://localhost:18081"
|
||||
Button:
|
||||
text: "Click to change\ndaemon address"
|
||||
Label:
|
||||
size_hint_y: 0.1
|
||||
BoxLayout:
|
||||
size_hint_y: 0.05
|
||||
orientation: 'horizontal'
|
||||
Label:
|
||||
text: 'Blockchain height:'
|
||||
MarkupLabel:
|
||||
id: blockheight_label
|
||||
BoxLayout:
|
||||
size_hint_y: 0.05
|
||||
orientation: 'horizontal'
|
||||
Label:
|
||||
text: 'Last block reward:'
|
||||
MarkupLabel:
|
||||
id: last_reward_label
|
||||
BoxLayout:
|
||||
size_hint_y: 0.05
|
||||
orientation: 'horizontal'
|
||||
Label:
|
||||
text: 'Last block time:'
|
||||
MarkupLabel:
|
||||
id: last_block_time_label
|
||||
BoxLayout:
|
||||
size_hint_y: 0.05
|
||||
orientation: 'horizontal'
|
||||
Label:
|
||||
text: 'Time since last block:'
|
||||
MarkupLabel:
|
||||
id: time_since_last_label
|
||||
|
||||
|
||||
<InitialPopup>:
|
||||
id: initial_popup
|
||||
title: "Initial Setup Window"
|
||||
auto_dismiss: "False"
|
||||
BoxLayout:
|
||||
orientation: 'vertical'
|
||||
Label:
|
||||
text: "It appears that this is your first time loading CryptoNote Kivy GUI\n(or you have deleted your CONFIG.file file).\nPlease select if you would like to create a new wallet, load an existing wallet, or exit the program"
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
padding: 30, 20, 30, 20
|
||||
Button:
|
||||
text: "Create\nNew\nWallet"
|
||||
on_press: root.createWalletPopup()
|
||||
Button:
|
||||
text: "Load\nExisting\nWallet"
|
||||
on_press: root.loadWalletPopup()
|
||||
Button:
|
||||
text: "Exit KivyWallet"
|
||||
on_press: root.quit()
|
||||
|
||||
|
||||
<CreateWalletPopup>:
|
||||
id: create_wallet_popup
|
||||
title: "Create Wallet Window"
|
||||
auto_dismiss: "False"
|
||||
wallet_name: wallet_name
|
||||
wallet_pw: wallet_pw
|
||||
repeat_wallet_pw: repeat_wallet_pw
|
||||
BoxLayout:
|
||||
padding: 60, 60, 60, 60
|
||||
orientation: 'vertical'
|
||||
Label:
|
||||
text: "Enter wallet name:"
|
||||
TabTextInput:
|
||||
id: wallet_name
|
||||
next: wallet_pw
|
||||
Label:
|
||||
text: "Enter wallet password:"
|
||||
TabTextInput:
|
||||
id: wallet_pw
|
||||
password: True
|
||||
next: repeat_wallet_pw
|
||||
Label:
|
||||
text: "Repeat wallet password:"
|
||||
TabTextInput:
|
||||
id: repeat_wallet_pw
|
||||
password: True
|
||||
next: wallet_pw
|
||||
Button:
|
||||
text: "Click to create wallet"
|
||||
on_press: root.createWallet()
|
||||
|
||||
|
||||
<LoadWalletPopup>:
|
||||
id: load_wallet_popup
|
||||
title: "Load Wallet Window"
|
||||
auto_dismiss: "False"
|
||||
wallet_path: wallet_path
|
||||
wallet_pw: wallet_pw
|
||||
repeat_wallet_pw: repeat_wallet_pw
|
||||
BoxLayout:
|
||||
padding: 60, 60, 60, 60
|
||||
orientation: 'vertical'
|
||||
MarkupLabel:
|
||||
text: "Enter wallet keys path (make sure you include file extension)\nExample - [b][color=00ffff]C:\\Users\\Satoshi\\SecretStuff\\Wallets\\Monero\\wallet.bin.keys[/b][/color]:"
|
||||
TabTextInput:
|
||||
id: wallet_path
|
||||
next: wallet_pw
|
||||
Label:
|
||||
text: "Enter wallet password:"
|
||||
TabTextInput:
|
||||
id: wallet_pw
|
||||
password: True
|
||||
next: repeat_wallet_pw
|
||||
Label:
|
||||
text: "Repeat wallet password:"
|
||||
TabTextInput:
|
||||
id: repeat_wallet_pw
|
||||
password: True
|
||||
next: wallet_path
|
||||
Label:
|
||||
text: "Note - this wallet will be set as your default wallet"
|
||||
Button:
|
||||
text: "Click to load wallet"
|
||||
on_press: root.loadWallet()
|
||||
|
||||
|
||||
<PasswordPopup>
|
||||
title: "Password entry popup"
|
||||
walletname_label: walletname_label
|
||||
wallet_pw: wallet_pw
|
||||
BoxLayout:
|
||||
orientation: "vertical"
|
||||
Label:
|
||||
id: walletname_label
|
||||
TabTextInput:
|
||||
id: wallet_pw
|
||||
password: True
|
||||
Button:
|
||||
text: "Click to launch wallet"
|
||||
on_press: root.launchWallet()
|
||||
|
||||
|
||||
<TransferPopup>
|
||||
transfer_popup_label: transfer_popup_label
|
||||
size_hint: 0.75, 0.75
|
||||
auto_dismiss: False
|
||||
title: "Transfer Popup"
|
||||
BoxLayout:
|
||||
orientation: 'vertical'
|
||||
Label:
|
||||
# text: "are you sure?"
|
||||
id: transfer_popup_label
|
||||
text: ""
|
||||
markup: True
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
Button:
|
||||
text: "Yes, transfer XMR."
|
||||
on_press: root.transfer()
|
||||
on_press: root.dismiss()
|
||||
Button:
|
||||
text: "No, cancel transaction."
|
||||
on_press: root.dismiss()
|
||||
|
||||
|
||||
<TxIDPopup>
|
||||
title: "Tx ID Popup"
|
||||
txid_popup_label: txid_popup_label
|
||||
BoxLayout:
|
||||
orientation: 'vertical'
|
||||
Label:
|
||||
font_size: 11
|
||||
markup: True
|
||||
id: txid_label
|
||||
text: ""
|
||||
on_ref_press: root.selecttxid()
|
||||
Button:
|
||||
text: "OK, dismiss."
|
||||
on_press: root.dismiss()
|
||||
|
||||
|
||||
<MarkupLabel>
|
||||
markup: True
|
||||
|
||||
|
||||
<TabTextInput>
|
||||
multiline: False
|
||||
+560
@@ -0,0 +1,560 @@
|
||||
# !/usr/bin/python
|
||||
from platform import system
|
||||
from kivy.app import App
|
||||
from kivy.config import Config
|
||||
from kivy.uix.accordion import Accordion
|
||||
from kivy.uix.button import Button
|
||||
from kivy.uix.label import Label
|
||||
from kivy.properties import ObjectProperty
|
||||
from kivy.core.clipboard import Clipboard
|
||||
from kivy.clock import Clock
|
||||
from kivy.uix.popup import Popup
|
||||
from kivy.storage.jsonstore import JsonStore
|
||||
from kivy.uix.textinput import TextInput
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import time
|
||||
from subprocess import PIPE, Popen, STDOUT
|
||||
from threading import Thread
|
||||
from Queue import Queue, Empty
|
||||
import shutil
|
||||
|
||||
from lib.checklastblock import CheckLastBlock
|
||||
from lib.savewallet import storeWallet
|
||||
from lib.transferfunds import transferfundsrpccall
|
||||
|
||||
|
||||
# Set POSIX argument for linux for something...
|
||||
ON_POSIX = 'posix' in sys.builtin_module_names
|
||||
|
||||
|
||||
# parser gets command line args
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.parse_args()
|
||||
|
||||
|
||||
# define functions to read output streams
|
||||
def enqueue_output(out, queue):
|
||||
for line in iter(out.readline, b''):
|
||||
queue.put(line)
|
||||
out.close()
|
||||
|
||||
|
||||
def read_output(process, stdout, queue):
|
||||
while True:
|
||||
out = stdout.readline()
|
||||
#print("Process is: "+process.poll())
|
||||
if out == '' and process.poll() != None:
|
||||
break
|
||||
if out != '':
|
||||
line = out.rstrip()
|
||||
queue.put_nowait(line)
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
# Function to split tx output lines
|
||||
def txSplit(line):
|
||||
split_line = line.split(': ')
|
||||
try:
|
||||
amount = float(split_line[1].split(',')[0])
|
||||
tx = split_line[2].strip('<>')
|
||||
date = split_line[0].split('.')[0]
|
||||
return amount, tx, date
|
||||
except ValueError:
|
||||
return "Error", "Error", "Error"
|
||||
except IndexError:
|
||||
return "Error", "Error", "Error"
|
||||
|
||||
|
||||
class MarkupLabel(Label):
|
||||
""" Label class with markup on by default """
|
||||
pass
|
||||
|
||||
|
||||
class TabTextInput(TextInput):
|
||||
""" Tab or enter to next TextInput class """
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.next = kwargs.pop('next', None)
|
||||
super(TabTextInput, self).__init__(*args, **kwargs)
|
||||
|
||||
def set_next(self, next):
|
||||
self.next = next
|
||||
|
||||
def _keyboard_on_key_down(self, window, keycode, text, modifiers):
|
||||
key, key_str = keycode
|
||||
if key in (9, 13) and self.next is not None:
|
||||
self.next.focus = True
|
||||
self.next.select_all()
|
||||
else:
|
||||
super(TabTextInput, self)._keyboard_on_key_down(window, keycode, text, modifiers)
|
||||
|
||||
|
||||
class InitialPopup(Popup):
|
||||
""" Initial popup widget """
|
||||
|
||||
def loadWalletPopup(self):
|
||||
self.dismiss()
|
||||
lwp = LoadWalletPopup()
|
||||
lwp.open()
|
||||
|
||||
def createWalletPopup(self):
|
||||
self.dismiss()
|
||||
cwp = CreateWalletPopup()
|
||||
cwp.open()
|
||||
|
||||
def quit(self):
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
class CreateWalletPopup(Popup):
|
||||
""" Wallet creation screen popup """
|
||||
wallet_name = ObjectProperty()
|
||||
wallet_pw = ObjectProperty()
|
||||
repeat_wallet_pw = ObjectProperty()
|
||||
|
||||
def createWallet(self):
|
||||
electrum_coming = False
|
||||
wallet_name = self.wallet_name.text
|
||||
wallet_pw = self.wallet_pw.text
|
||||
if self.wallet_pw.text == self.repeat_wallet_pw.text:
|
||||
p = Popen(["simplewallet", "--generate-new-wallet",
|
||||
"./" + wallet_name.replace('.', '') + "_walletData/" + wallet_name,
|
||||
"--password", wallet_pw],
|
||||
stdout=PIPE,
|
||||
stdin=PIPE,
|
||||
bufsize=1,
|
||||
close_fds=ON_POSIX)
|
||||
if not os.path.exists('./{0}_walletData'.format(wallet_name.replace('.', ''))):
|
||||
os.mkdir('./{0}_walletData'.format(wallet_name.replace('.', '')))
|
||||
else:
|
||||
sys.exit(7777)
|
||||
q = Queue()
|
||||
t = Thread(target=enqueue_output, args=(p.stdout, q))
|
||||
t.daemon = True # thread dies with the program
|
||||
t.start()
|
||||
t_start = time.time()
|
||||
while time.time() - t_start < 2:
|
||||
try:
|
||||
line = q.get_nowait() # or q.get(timeout=.1)
|
||||
if "new wallet:" in line:
|
||||
address = line.rstrip().split(': ')[1]
|
||||
if "view key:" in line:
|
||||
view_key = line.rstrip().split(': ')[1]
|
||||
if 130 < len(line.rstrip()) < 350:
|
||||
electrum = line.rstrip()
|
||||
if "PLEASE NOTE:" in line:
|
||||
electrum_coming = line.rstrip()
|
||||
print("simplewallet output:", line.rstrip())
|
||||
except Empty:
|
||||
# print('no output yet')
|
||||
pass
|
||||
else: # got line
|
||||
# print(line)
|
||||
pass
|
||||
# time.sleep(0.1)
|
||||
p.kill()
|
||||
# os.system("taskkill /im simplewallet.exe /f")
|
||||
# print(p.pid)
|
||||
with open('./{0}_walletData/info.txt'.format(wallet_name.replace('.', '')), 'w') as f:
|
||||
f.write("Name:\n{0}\n\nAddress:\n{1}\n\nView key:\n{2}\n\nElectrum seed:\n{3}".format(
|
||||
wallet_name, address, view_key, electrum))
|
||||
with open("./CONFIG.file", 'w') as f:
|
||||
f.write(wallet_name)
|
||||
self.dismiss()
|
||||
content = Button(
|
||||
text="Your wallet has been created in the local directory {0}_walletData\nThe info.txt document in that folder contains your wallet recovery seed.\nPlease keep this seed safe, you can restore a corrupted/lost wallet with it.\nSomeone else can also bypass your password and steal your XMR with it.\nI suggest deleting or encrypting this file.".format(
|
||||
wallet_name))
|
||||
walletCreatedPopup = Popup(title="Wallet created window",
|
||||
content=content)
|
||||
content.bind(on_press=walletCreatedPopup.dismiss)
|
||||
walletCreatedPopup.open()
|
||||
App.get_running_app().root.launchWallet(wallet_name, wallet_pw)
|
||||
else:
|
||||
content = Button(text="Check passwords!!!\nClick to dismiss")
|
||||
pwErrorPopup = Popup(title="Password match error window",
|
||||
content=content)
|
||||
content.bind(on_press=pwErrorPopup.dismiss)
|
||||
pwErrorPopup.open()
|
||||
|
||||
|
||||
class LoadWalletPopup(Popup):
|
||||
""" Wallet loading screen popup """
|
||||
wallet_path = ObjectProperty()
|
||||
wallet_pw = ObjectProperty()
|
||||
repeat_wallet_pw = ObjectProperty()
|
||||
|
||||
def loadWallet(self):
|
||||
split_name = os.path.split(self.wallet_path.text)[1].split('.')
|
||||
wallet_name = '.'.join(tuple(split_name[0:len(split_name) - 1]))
|
||||
print(split_name, wallet_name)
|
||||
wallet_pw = self.wallet_pw.text
|
||||
wallet_error = False
|
||||
if self.wallet_pw.text == self.repeat_wallet_pw.text:
|
||||
p = Popen(["simplewallet", "--wallet-file",
|
||||
self.wallet_path.text,
|
||||
"--password", wallet_pw],
|
||||
stdout=PIPE,
|
||||
stdin=PIPE,
|
||||
bufsize=1,
|
||||
close_fds=ON_POSIX)
|
||||
q = Queue()
|
||||
t = Thread(target=enqueue_output, args=(p.stdout, q))
|
||||
t.daemon = True # thread dies with the program
|
||||
t.start()
|
||||
t_start = time.time()
|
||||
while time.time() - t_start < 2:
|
||||
try:
|
||||
line = q.get_nowait() # or q.get(timeout=.1)
|
||||
print("simplewallet output:", line.rstrip())
|
||||
if "Opened wallet: " in line.rstrip():
|
||||
address = line.rstrip().split(": ")[1]
|
||||
if "Error: failed" in line.rstrip():
|
||||
wallet_error = True
|
||||
except Empty:
|
||||
# print('no output yet')
|
||||
pass
|
||||
else: # got line
|
||||
pass
|
||||
p.kill()
|
||||
if not wallet_error:
|
||||
if not os.path.exists("./{0}_walletData".format(wallet_name.replace('.', ''))):
|
||||
os.mkdir("./{0}_walletData".format(wallet_name.replace('.', '')))
|
||||
with open("./CONFIG.file", 'w') as f:
|
||||
f.write(wallet_name)
|
||||
with open("./{0}_walletData/{1}.address.txt".format(wallet_name.replace('.', ''), wallet_name), 'w') as f:
|
||||
f.write(address)
|
||||
shutil.copyfile(self.wallet_path.text,
|
||||
"./{0}_walletData/{1}.keys".format(wallet_name.replace('.', ''), wallet_name))
|
||||
self.dismiss()
|
||||
content = Button(
|
||||
text="Your wallet keys file has been copied to the local directory {0}_walletData\nThe original has not been disturbed.".format(
|
||||
wallet_name))
|
||||
walletCopiedPopup = Popup(title="Wallet keys copied window",
|
||||
content=content)
|
||||
content.bind(on_press=walletCopiedPopup.dismiss)
|
||||
walletCopiedPopup.open()
|
||||
App.get_running_app().root.launchWallet(wallet_name, wallet_pw)
|
||||
else:
|
||||
content = Button(text="Wallet import error!\nClick to start over")
|
||||
pwErrorPopup = Popup(title="Wallet import error window",
|
||||
content=content)
|
||||
content.bind(on_press=pwErrorPopup.dismiss)
|
||||
ip = InitialPopup()
|
||||
content.bind(on_press=ip.open)
|
||||
pwErrorPopup.open()
|
||||
|
||||
|
||||
class PasswordPopup(Popup):
|
||||
""" Popup class to get pw on launch with CONFIG.file """
|
||||
wallet_pw = ObjectProperty()
|
||||
walletname_label = ObjectProperty()
|
||||
|
||||
def __init__(self, wallet_name):
|
||||
super(PasswordPopup, self).__init__()
|
||||
self.wallet_name = wallet_name
|
||||
if not App.get_running_app().root.wallet_error:
|
||||
self.walletname_label.text = "Please enter your password for {0} account:".format(self.wallet_name)
|
||||
if App.get_running_app().root.wallet_error:
|
||||
self.walletname_label.text = "There seems to be a problem with binary file,\nPlease enter your password to attempt rebuild of {0} account:".format(
|
||||
self.wallet_name)
|
||||
|
||||
def launchWallet(self):
|
||||
wallet_pw = self.wallet_pw.text
|
||||
App.get_running_app().root.launchWallet(self.wallet_name, wallet_pw)
|
||||
self.dismiss()
|
||||
|
||||
|
||||
class TransferPopup(Popup):
|
||||
""" Popup class to initiate XMR transfer """
|
||||
transfer_popup_label = ObjectProperty()
|
||||
|
||||
def __init__(self, amount, address, mixin, paymentid):
|
||||
super(TransferPopup, self).__init__()
|
||||
self.amount = amount
|
||||
self.address = address
|
||||
self.mixin = mixin
|
||||
self.paymentid = paymentid
|
||||
self.popuptext = "Are you sure you want to send {0:0.9f} XMR\n to [size=8]{1}[/size]\n with mixin count {2} and payment id [size=8]{3}[/size]".format(
|
||||
float(amount), address, mixin, paymentid)
|
||||
self.transfer_popup_label.text = self.popuptext
|
||||
|
||||
def transfer(self):
|
||||
txid = transferfundsrpccall(self.amount, self.address, self.mixin, self.paymentid)
|
||||
txid_popup = TxIDPopup(txid)
|
||||
txid_popup.open()
|
||||
|
||||
|
||||
class TxIDPopup(Popup):
|
||||
txid_label = ObjectProperty()
|
||||
def __init__(self, txid):
|
||||
super(TxIDPopup, self).__init__()
|
||||
self.txid = txid
|
||||
self.txid_label.text = "TxID: [ref=txid]{0}[/ref]\n(Click TxID to copy to clipboard)".format(txid)
|
||||
|
||||
def selecttxid(self):
|
||||
Clipboard.put(self.txid)
|
||||
|
||||
|
||||
class RootWidget(Accordion):
|
||||
"""Root Kivy accordion widget class"""
|
||||
wallet_error = None
|
||||
# Transfer XMR id items
|
||||
address_input_textinput = ObjectProperty()
|
||||
amount_input_textinput = ObjectProperty()
|
||||
mixin_input_textinput = ObjectProperty()
|
||||
paymentid_input_textinput = ObjectProperty()
|
||||
# Wallet account id items
|
||||
wallet_account_label = ObjectProperty()
|
||||
wallet_address_label = ObjectProperty()
|
||||
unlocked_balance_label = ObjectProperty()
|
||||
total_balance_label = ObjectProperty()
|
||||
calculated_balance_label = ObjectProperty()
|
||||
# Daemon id items
|
||||
daemon_server_textinput = ObjectProperty()
|
||||
blockheight_label = ObjectProperty()
|
||||
last_reward_label = ObjectProperty()
|
||||
last_block_time_label = ObjectProperty()
|
||||
time_since_last_label = ObjectProperty()
|
||||
wallet_block_label = ObjectProperty()
|
||||
blockheight = 0
|
||||
# Process, queue, and thread variables
|
||||
daemon_queue = Queue()
|
||||
daemon_thread = None
|
||||
wallet_process = None
|
||||
wallet_queue = Queue()
|
||||
wallet_thread = None
|
||||
# Other variables
|
||||
calculated_balance = 0.0
|
||||
total_balance = 0.0
|
||||
unlocked_balance = 0.0
|
||||
temp_tx_amount = 0.0
|
||||
temp_tx_hash = ""
|
||||
temp_tx_paymentid = ""
|
||||
wallet_save_time = None
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(RootWidget, self).__init__(**kwargs)
|
||||
self.daemon_thread = Thread(target=self.checkDaemonStatus,
|
||||
args=(self.daemon_queue, self.daemon_server_textinput.text))
|
||||
self.daemon_thread.daemon = True
|
||||
self.daemon_thread.start()
|
||||
if os.path.isfile('./CONFIG.file'):
|
||||
with open('./CONFIG.file', 'r') as f:
|
||||
self.wallet_name = f.read().rstrip()
|
||||
print(self.wallet_name)
|
||||
Clock.schedule_once(self.initialPassword, 0.5)
|
||||
else:
|
||||
Clock.schedule_once(self.initialConfig, 0.5)
|
||||
Clock.schedule_interval(self.checkDaemon, 5)
|
||||
|
||||
|
||||
def initialConfig(self, dt):
|
||||
ip = InitialPopup()
|
||||
ip.open()
|
||||
|
||||
def initialPassword(self, dt):
|
||||
gp = PasswordPopup(self.wallet_name)
|
||||
gp.open()
|
||||
|
||||
def checkDaemonStatus(self, daemon_queue, server):
|
||||
"""Class to be threaded for checking bitmonerod status"""
|
||||
# print(server)
|
||||
height, reward, timesince, localtime = CheckLastBlock(server + "/json_rpc")
|
||||
daemon_queue.put((height, reward, timesince, localtime))
|
||||
# print("sleeping")
|
||||
time.sleep(1)
|
||||
self.checkDaemonStatus(daemon_queue, self.daemon_server_textinput.text)
|
||||
|
||||
def checkDaemon(self, dt):
|
||||
try:
|
||||
height, reward, timesince, localtime = self.daemon_queue.get_nowait()
|
||||
self.blockheight = int(height)
|
||||
self.blockheight_label.text = "[b][color=00ffff]{0}[/b][/color]".format(height)
|
||||
self.last_reward_label.text = "[b][color=00ffff]{0:.2f}[/b][/color] XMR".format(reward * 1e-12)
|
||||
self.last_block_time_label.text = "[b][color=00ffff]{0}[/b][/color]".format(localtime)
|
||||
self.time_since_last_label.text = "[b][color=00ffff]{0:.0f}[/b][/color] seconds".format(timesince)
|
||||
except:
|
||||
pass
|
||||
|
||||
def launchWallet(self, wallet_name, wallet_pw):
|
||||
with open("./{0}_walletData/{1}.address.txt".format(wallet_name.replace('.', ''), wallet_name), 'r') as f:
|
||||
self.address = f.read().rstrip()
|
||||
self.wallet_account_label.text = "[b][color=00ffff]{0}[/b][/color]".format(wallet_name)
|
||||
self.wallet_address_label.text = "[b][color=00ffff][ref=Address]{0}[/ref][/b][/color]".format(self.address)
|
||||
if not os.path.isfile("./{0}_walletData/{1}".format(wallet_name.replace('.', ''), wallet_name)):
|
||||
self.wallet_process = Popen(["simplewallet.exe", "--wallet-file", "./{0}_walletData/{1}".format(
|
||||
wallet_name.replace('.', ''), wallet_name), "--password", wallet_pw],
|
||||
stdin=PIPE,
|
||||
stdout=PIPE,
|
||||
stderr=STDOUT,
|
||||
bufsize=1)
|
||||
self.wallet_process.communicate(input="exit\r\n")
|
||||
self.wallet_process.kill()
|
||||
# try:
|
||||
# system("taskkill /im simplewallet.exe /f")
|
||||
# except:
|
||||
# print("Simplewallet.exe not running")
|
||||
if os.path.isfile("./{0}_walletData/tx.txt".format(wallet_name.replace('.', ''))):
|
||||
with open("./{0}_walletData/tx.txt".format(wallet_name.replace('.', ''), 'r')) as previous_txs:
|
||||
txs = previous_txs.read().split('\n')
|
||||
for idx, line in enumerate(txs):
|
||||
this_amount, this_tx, this_date = txSplit(line)
|
||||
if idx < len(txs) - 1:
|
||||
next_amount, next_tx, date = txSplit(txs[idx+1])
|
||||
else:
|
||||
next_amount, next_tx, date = "Done", "Done", "Done"
|
||||
if this_tx != next_tx and self.temp_tx_amount == 0.0:
|
||||
if "Received" in line:
|
||||
l = Label(text="Received {0:0.3f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
|
||||
size_hint_y=None, height=15, font_size=9)
|
||||
self.ids.tx_list.add_widget(l)
|
||||
self.calculated_balance += this_amount
|
||||
elif "Spent" in line:
|
||||
l = Label(text="Spent {0:0.3f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
|
||||
size_hint_y=None, height=15, font_size=9)
|
||||
self.ids.tx_list.add_widget(l)
|
||||
self.calculated_balance -= this_amount
|
||||
elif this_tx == next_tx and self.temp_tx_amount == 0.0:
|
||||
self.temp_tx_amount += this_amount + next_amount
|
||||
elif this_tx == next_tx and self.temp_tx_amount != 0.0:
|
||||
self.temp_tx_amount += next_amount
|
||||
elif this_tx != next_tx and self.temp_tx_amount != 0.0:
|
||||
if "Received" in line:
|
||||
l = Label(text="Received {0:0.3f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
|
||||
size_hint_y=None, height=15, font_size=9)
|
||||
self.ids.tx_list.add_widget(l)
|
||||
self.calculated_balance += self.temp_tx_amount
|
||||
elif "Spent" in line:
|
||||
l = Label(text="Spent {0:0.3f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
|
||||
size_hint_y=None, height=15, font_size=9)
|
||||
self.ids.tx_list.add_widget(l)
|
||||
self.calculated_balance -= self.temp_tx_amount
|
||||
self.temp_tx_amount = 0.0
|
||||
self.temp_tx_amount = 0.0
|
||||
self.calculated_balance_label.text = "[b][color=00ffff]{0:.3f}[/b][/color]".format(self.calculated_balance)
|
||||
self.wallet_process = Popen(["simplewallet", "--wallet-file", "./{0}_walletData/{1}.keys".format(
|
||||
wallet_name.replace('.', ''), wallet_name), "--password", wallet_pw,
|
||||
"--daemon-address", self.daemon_server_textinput.text, "--rpc-bind-port", "19091"],
|
||||
stdin=PIPE,
|
||||
stdout=PIPE,
|
||||
stderr=STDOUT,
|
||||
bufsize=1)
|
||||
self.wallet_thread = Thread(target=read_output,
|
||||
args=(self.wallet_process, self.wallet_process.stdout, self.wallet_queue))
|
||||
# self.wallet_thread = Thread(target=enqueue_output,
|
||||
# args=(self.wallet_process.stdout, self.wallet_queue))
|
||||
self.wallet_thread.daemon = True # thread dies with the program
|
||||
self.wallet_thread.start()
|
||||
Clock.schedule_interval(self.readWalletQueue, .01)
|
||||
# Clock.schedule_interval(self.saveWallet, 60)
|
||||
|
||||
def readWalletQueue(self, dt):
|
||||
print(self.wallet_thread.is_alive)
|
||||
try:
|
||||
print("trying")
|
||||
newLine = self.wallet_queue.get_nowait()
|
||||
# with open("rpcwallet.log", 'a') as logfile:
|
||||
# logfile.write(newLine+'\n')
|
||||
print newLine
|
||||
if "Wallet initialize failed: failed to read file" in newLine:
|
||||
self.wallet_thread.join()
|
||||
self.wallet_error = True
|
||||
os.remove("./{0}_walletData/{1}".format(self.wallet_name.replace('.', ''), self.wallet_name))
|
||||
Clock.schedule_once(self.initialPassword, 0.5)
|
||||
if "height:" in newLine:
|
||||
height = newLine.split(", ")[1].split(": ")[1]
|
||||
self.wallet_block_label.text = "[b][color=00ffff]{0}[/b][/color] of [b][color=00ffff]{1}[/b][/color]".format(
|
||||
height, self.blockheight)
|
||||
elif "height " in newLine:
|
||||
height = newLine.split(", ")[1].split(" ")[1]
|
||||
self.wallet_block_label.text = "[b][color=00ffff]{0}[/b][/color] of [b][color=00ffff]{1}[/b][/color]".format(
|
||||
height, self.blockheight)
|
||||
elif "Refresh done," in newLine:
|
||||
print("refresh done")
|
||||
split_line = newLine.split(',')
|
||||
self.total_balance = float(split_line[2].split(': ')[1])
|
||||
self.unlocked_balance = float(split_line[3].split(': ')[1])
|
||||
self.total_balance_label.text = "[b][color=00ffff]{0:.3f}[/b][/color]".format(self.total_balance)
|
||||
self.unlocked_balance_label.text = "[b][color=00ffff]{0:.3f}[/b][/color]".format(self.unlocked_balance)
|
||||
if not self.wallet_save_time:
|
||||
print("First save launching!")
|
||||
Clock.schedule_once(self.saveWallet, 0.1)
|
||||
self.wallet_save_time = time.time()
|
||||
print("Wallet saved at: {0}".format(self.wallet_save_time))
|
||||
if self.wallet_save_time:
|
||||
if time.time() - self.wallet_save_time > 1800:
|
||||
Clock.schedule_once(self.saveWallet, 0.1)
|
||||
print(time.time(), self.wallet_save_time, "saving")
|
||||
self.wallet_save_time = time.time()
|
||||
elif "Received money" in newLine and "with tx" in newLine:
|
||||
with open("./{0}_walletData/tx.txt".format(self.wallet_name), 'a') as tx_file:
|
||||
this_amount, this_tx, this_date = txSplit(newLine)
|
||||
tx_file.write(newLine + '\n')
|
||||
self.calculated_balance += this_amount
|
||||
self.calculated_balance_label.text = "[b][color=00ffff]{0:.3f}[/b][/color]".format(
|
||||
self.calculated_balance)
|
||||
l = Label(text="Received {0:0.3f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
|
||||
size_hint_y=None, height=15, font_size=9)
|
||||
self.ids.tx_list.add_widget(l)
|
||||
elif "Spent money" in newLine and "with tx" in newLine:
|
||||
with open("./{0}_walletData/tx.txt".format(self.wallet_name), 'a') as tx_file:
|
||||
this_amount, this_tx, this_date = txSplit(newLine)
|
||||
tx_file.write(newLine + '\n')
|
||||
self.calculated_balance -= this_amount
|
||||
l = Label(text="Spent {0:0.3f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
|
||||
size_hint_y=None, height=15, font_size=9)
|
||||
self.ids.tx_list.add_widget(l)
|
||||
# elif "Payment found" in newLine:
|
||||
# with open("./{0}_walletData/tx.txt".format(self.wallet_name), 'a') as tx_file:
|
||||
# tx_file.write(newLine + '\n')
|
||||
except Empty:
|
||||
pass
|
||||
# if not self.wallet_thread.is_alive():
|
||||
# print("dead")
|
||||
# self.wallet_thread.start()
|
||||
# Clock.schedule_interval(self.readWalletQueue, 0.01)
|
||||
|
||||
def saveWallet(self, dt):
|
||||
print("Launching save thread")
|
||||
save_thread = Thread(target=storeWallet)
|
||||
save_thread.daemon = True
|
||||
save_thread.start()
|
||||
save_thread.join()
|
||||
print("Finished save thread")
|
||||
|
||||
def selectAddress(self):
|
||||
"""copy address to clipboard when user clicks"""
|
||||
print('User clicked on ', self.address)
|
||||
self.daemon_server_textinput.copy(self.address)
|
||||
|
||||
def transferfunds(self):
|
||||
"""initiate transfer of funds to new address"""
|
||||
try:
|
||||
float(self.amount_input_textinput.text)
|
||||
tp = TransferPopup(self.amount_input_textinput.text, self.address_input_textinput.text,
|
||||
self.mixin_input_textinput.text, self.paymentid_input_textinput.text)
|
||||
tp.open()
|
||||
except ValueError:
|
||||
print("no,no")
|
||||
|
||||
|
||||
class KVNewApp(App):
|
||||
def build(self):
|
||||
return RootWidget()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Config.set('kivy', 'exit_on_escape', 0)
|
||||
Config.set('kivy', 'window_icon', "./lilicon.ico")
|
||||
KVNewApp().run()
|
||||
try:
|
||||
App.get_running_app().root.wallet_process.kill()
|
||||
except:
|
||||
print("Wallet process not running")
|
||||
# try:
|
||||
# system("taskkill /im simplewallet.exe /f")
|
||||
# except:
|
||||
# print("Simplewallet.exe not running")
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Reference in New Issue
Block a user