mirror of
https://github.com/jwinterm/cryptonoteRPCwalletGUI.git
synced 2026-10-17 05:51:33 +02:00
Initial commit for Kivy GUI wallet
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
def bitmonerodloader():
|
||||
"""Start bitmonerod and/or simplewallet and collect wallet name and address"""
|
||||
#Start bitmonerod daemon if not running
|
||||
if os.name == 'nt':
|
||||
daemonproc = subprocess.Popen("start bitmonerod --rpc-bind-port 18081",
|
||||
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
elif os.name == 'posix':
|
||||
daemonproc = subprocess.Popen(['./bitmonerod --rpc-bind-port 18081'],
|
||||
creationflags=subprocess.CREATE_NEW_CONSOLE,
|
||||
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
@@ -0,0 +1,38 @@
|
||||
import requests
|
||||
import json
|
||||
|
||||
serverURL = 'http://localhost:8082/json_rpc'
|
||||
|
||||
|
||||
def checkbalancerpccall():
|
||||
"""function to make rpc call to simplewallet to get current balance"""
|
||||
payload = json.dumps({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getbalance",
|
||||
"params": {}
|
||||
})
|
||||
print 'attempting rpc call'
|
||||
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
|
||||
rawbalance = str(output[u'result'][u'balance']/1e12)
|
||||
rawunlockedbalance = str(output[u'result'][u'unlocked_balance']/1e12)
|
||||
|
||||
#Format data for kivy
|
||||
balance = '[color=00ff00]'+rawbalance+'[/color]'
|
||||
unlockedbalance = '[color=00ff00]'+rawunlockedbalance+'[/color]'
|
||||
return balance, unlockedbalance
|
||||
|
||||
|
||||
except:
|
||||
#Return out of sync if bitmonerod is not ready
|
||||
return '[color=ff0000]out of sync[/color]', '[color=ff0000]out of sync[/color]'
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
checkbalance()
|
||||
@@ -0,0 +1,42 @@
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
|
||||
serverURL = 'http://localhost:8081/json_rpc'
|
||||
|
||||
headers = {'content-type': 'application/json'}
|
||||
|
||||
payload = json.dumps({
|
||||
"jsonrpc": "2.0",
|
||||
"id": "test",
|
||||
"method": "getlastblockheader"
|
||||
})
|
||||
|
||||
|
||||
def checklastblockrpccall():
|
||||
synced = False
|
||||
while synced == False:
|
||||
resp = requests.get(serverURL, headers=headers, data=payload)
|
||||
output = json.loads(resp.text)
|
||||
try:
|
||||
output[u'result'][u'status'] == 'OK'
|
||||
synced = True
|
||||
except:
|
||||
time.sleep(2)
|
||||
print "Waiting for bitmonerod client to sync with network..."
|
||||
|
||||
try:
|
||||
if output[u'error'][u'message'] == 'Core is busy':
|
||||
time.sleep(3)
|
||||
except:
|
||||
print '2nd'
|
||||
|
||||
|
||||
print "Client is synced with the network."
|
||||
print output
|
||||
time.sleep(4)
|
||||
|
||||
return output
|
||||
|
||||
if __name__ == "__main__":
|
||||
checklastblockrpccall()
|
||||
@@ -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,43 @@
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
import checklastblock
|
||||
|
||||
def simplewalletloader(walletname, walletpw, queue):
|
||||
"""Function to create and/or open wallet in simplewallet rpc mode"""
|
||||
|
||||
#Generate wallet if file doesn't exist in local directory
|
||||
if not os.path.isfile('./'+walletname):
|
||||
print "Generating wallet file " + walletname
|
||||
if os.name == 'nt':
|
||||
walletgen = subprocess.Popen(
|
||||
"simplewallet --generate-new-wallet " + walletname + " --password " + walletpw,
|
||||
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
elif os.name == 'posix':
|
||||
walletgen = subprocess.Popen(
|
||||
"./simplewallet --generate-new-wallet " + walletname + " --password " + walletpw,
|
||||
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
creationflags=subprocess.CREATE_NEW_CONSOLE)
|
||||
|
||||
time.sleep(7)
|
||||
walletgen.terminate()
|
||||
|
||||
#Launch simplewallet in rpc mode
|
||||
print "***Opening ___" + walletname + "___ wallet file rpc interface***"
|
||||
if os.name == 'nt':
|
||||
walletproc = subprocess.Popen("start simplewallet --wallet {0} --password {1} --rpc-bind-port 8082".format(walletname, walletpw),
|
||||
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
elif os.name == 'posix':
|
||||
walletproc = subprocess.Popen(["./simplewallet --wallet {0} --password {1} --rpc-bind-port 8082".format(
|
||||
walletname, walletpw)], creationflags=subprocess.CREATE_NEW_CONSOLE)
|
||||
|
||||
#Read address file to get address
|
||||
with open(walletname + ".address.txt", "r") as addressfile:
|
||||
rawaddress = addressfile.read().replace('\n', '')
|
||||
|
||||
#Format data for display in kivy
|
||||
walletname = walletname + ' wallet file has been opened'
|
||||
address = '[color=00ffff][ref=addressselection]' + rawaddress + '[/ref][/color]'
|
||||
|
||||
queue.put((walletname, address, rawaddress))
|
||||
@@ -0,0 +1,42 @@
|
||||
import requests
|
||||
import json
|
||||
from ctypes import c_uint64
|
||||
|
||||
serverURL = 'http://localhost:8082/json_rpc'
|
||||
|
||||
|
||||
def transferfundsrpccall(amount, address, mixin):
|
||||
"""function to transfer funds to a single address"""
|
||||
atomicamount = c_uint64(int((float(amount)*1e12)-1e6))
|
||||
address = str(address)
|
||||
mixin = int(mixin)
|
||||
mro_fee = c_uint64(int(1e6))
|
||||
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
|
||||
|
||||
except:
|
||||
print "transfer error :0 !!!"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
checkbalance()
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
#:kivy 1.8.0
|
||||
|
||||
<RootWidget>:
|
||||
cols: 1
|
||||
input_name: name_input
|
||||
input_pw: pw_input
|
||||
label_myaddress: myaddress_label
|
||||
label_balance: balance_label
|
||||
label_unlockedbalance: unlockedbalance_label
|
||||
input_address: address_input
|
||||
input_amount: amount_input
|
||||
input_mixin: mixin_input
|
||||
input_paymentid: paymentid_input
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: 0.4
|
||||
Label:
|
||||
text: "[b]Kivy Monero/Cryptonote GUI RPC Wallet[/b]"
|
||||
markup: True
|
||||
font_size: 20
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: 0.1
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: 0.35
|
||||
Label:
|
||||
Button:
|
||||
size_hint_x: 1.7
|
||||
text: "Launch bitmonerod daemon"
|
||||
on_press: root.launchdaemon()
|
||||
Label:
|
||||
Button:
|
||||
size_hint_x: 1.7
|
||||
text: "Launch simplewallet daemon"
|
||||
on_press: root.launchwallet()
|
||||
Label:
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: 0.2
|
||||
|
||||
BoxLayout:
|
||||
padding: 10,0,40,0
|
||||
size_hint_y: 0.3
|
||||
Label:
|
||||
text: "Wallet name: "
|
||||
size_hint_x: 0.2
|
||||
font_size: 16
|
||||
TextInput:
|
||||
id: name_input
|
||||
size_hint_x: 0.8
|
||||
font_size: 12
|
||||
text: root.walletname
|
||||
|
||||
BoxLayout:
|
||||
padding: 10,0,40,0
|
||||
size_hint_y: 0.3
|
||||
Label:
|
||||
text: "Wallet password: "
|
||||
size_hint_x: 0.2
|
||||
font_size: 16
|
||||
TextInput:
|
||||
id: pw_input
|
||||
size_hint_x: 0.8
|
||||
font_size: 12
|
||||
text: root.walletpw
|
||||
password: True
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: 0.5
|
||||
padding: 10,0,80,0
|
||||
Label:
|
||||
text: "Wallet address: \n [size=10](click address to copy)[/size]"
|
||||
markup: True
|
||||
size_hint_x: 0.3
|
||||
font_size: 16
|
||||
halign: 'center'
|
||||
Label:
|
||||
id: myaddress_label
|
||||
text: "[ref=addressselection]uninitialized[/ref]"
|
||||
markup: True
|
||||
size_hint_x: 0.7
|
||||
font_size: 10
|
||||
on_ref_press: root.selectaddress()
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: 0.3
|
||||
Label:
|
||||
text: "Balance: "
|
||||
size_hint_x: 0.3
|
||||
font_size: 16
|
||||
|
||||
Label:
|
||||
id: balance_label
|
||||
text: root.balance
|
||||
size_hint_x: 0.7
|
||||
markup: True
|
||||
font_size: 16
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: 0.3
|
||||
Label:
|
||||
text: "Unlocked balance: "
|
||||
size_hint_x: 0.3
|
||||
font_size: 16
|
||||
Label:
|
||||
id: unlockedbalance_label
|
||||
text: root.unlockedbalance
|
||||
size_hint_x: 0.7
|
||||
markup: True
|
||||
font_size: 16
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: 0.35
|
||||
Label:
|
||||
Button:
|
||||
text: "Refresh balance"
|
||||
on_press: root.checkbalance()
|
||||
font_size: 20
|
||||
Label:
|
||||
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: 0.2
|
||||
|
||||
|
||||
BoxLayout:
|
||||
padding: 10,0,40,0
|
||||
size_hint_y: 0.3
|
||||
Label:
|
||||
text: "Send to address:"
|
||||
size_hint_x: 0.2
|
||||
TextInput:
|
||||
id: address_input
|
||||
size_hint_x: 0.8
|
||||
font_size: 10
|
||||
multiline: False
|
||||
|
||||
|
||||
BoxLayout:
|
||||
padding: 10,0,40,0
|
||||
size_hint_y: 0.3
|
||||
Label:
|
||||
text: "Amount MRO:"
|
||||
size_hint_x: 0.2
|
||||
TextInput:
|
||||
id: amount_input
|
||||
size_hint_x: 0.8
|
||||
font_size: 10
|
||||
multiline: False
|
||||
|
||||
|
||||
BoxLayout:
|
||||
padding: 10,0,40,0
|
||||
size_hint_y: 0.3
|
||||
Label:
|
||||
text: "Mixin amount:"
|
||||
size_hint_x: 0.2
|
||||
TextInput:
|
||||
id: mixin_input
|
||||
size_hint_x: 0.8
|
||||
font_size: 10
|
||||
multiline: False
|
||||
|
||||
|
||||
BoxLayout:
|
||||
padding: 10,0,40,0
|
||||
size_hint_y: 0.3
|
||||
Label:
|
||||
text: "Payment ID:"
|
||||
size_hint_x: 0.2
|
||||
TextInput:
|
||||
id: paymentid_input
|
||||
size_hint_x: 0.8
|
||||
font_size: 10
|
||||
text: "DISABLED!!! Do not send funds to exchanges. Disabled payment id field is required for depositing on exchanges!"
|
||||
multiline: False
|
||||
|
||||
|
||||
BoxLayout:
|
||||
padding: 200,0,200,0
|
||||
size_hint_y: 0.35
|
||||
Button:
|
||||
text: "Transfer funds"
|
||||
on_press: root.transferfunds()
|
||||
font_size: 20
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: 0.1
|
||||
@@ -0,0 +1,80 @@
|
||||
from kivy.app import App
|
||||
from kivy.uix.gridlayout import GridLayout
|
||||
from kivy.uix.boxlayout import BoxLayout
|
||||
from kivy.uix.button import Button
|
||||
from kivy.uix.label import Label
|
||||
from kivy.uix.textinput import TextInput
|
||||
from kivy.properties import ObjectProperty
|
||||
from kivy.core.clipboard import Clipboard
|
||||
|
||||
from functions.bitmonerodloader import bitmonerodloader
|
||||
from functions.checkbalance import checkbalancerpccall
|
||||
from functions.transferfunds import transferfundsrpccall
|
||||
from functions.simplewalletloader import simplewalletloader
|
||||
|
||||
from sys import argv
|
||||
from multiprocessing import Process, Queue
|
||||
|
||||
class RootWidget(GridLayout):
|
||||
"""Root Kivy widget class"""
|
||||
#Ininitalize variables
|
||||
if len(argv) == 1:
|
||||
walletname, walletpw = "", ""
|
||||
elif len(argv) == 3:
|
||||
walletname, walletpw = argv[1], argv[2]
|
||||
address, rawaddress = "uninitialized", "uninitialized"
|
||||
balance, unlockedbalance = "uninitialized", "uninitialized"
|
||||
|
||||
#Setup object properties to be modified/used
|
||||
input_name = ObjectProperty()
|
||||
input_pw = ObjectProperty()
|
||||
label_myaddress = ObjectProperty()
|
||||
label_balance = ObjectProperty()
|
||||
label_unlockedbalance = ObjectProperty()
|
||||
input_address = ObjectProperty()
|
||||
input_amount = ObjectProperty()
|
||||
input_mixin = ObjectProperty()
|
||||
|
||||
walletqueue = Queue()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(RootWidget, self).__init__(**kwargs)
|
||||
|
||||
def launchdaemon(self):
|
||||
"""launch the bitmonerod daemon in rpc mode"""
|
||||
bitmonerodloader()
|
||||
|
||||
def launchwallet(self):
|
||||
"""create wallet if necessary and then launch in rpc mode"""
|
||||
walletthread = Process(target=simplewalletloader, args=(self.input_name.text, self.input_pw.text, self.walletqueue))
|
||||
walletthread.start()
|
||||
walletthread.join()
|
||||
self.walletname, self.address, self.rawaddress = self.walletqueue.get()
|
||||
self.input_name.text = self.walletname
|
||||
self.input_name.background_color = (0.1,0.8,0.8,1)
|
||||
self.label_myaddress.text = self.address
|
||||
|
||||
def checkbalance(self):
|
||||
"""get balance info from rpc"""
|
||||
self.balance, self.unlockedbalance = checkbalancerpccall()
|
||||
self.label_balance.text = self.balance
|
||||
self.label_unlockedbalance.text = self.unlockedbalance
|
||||
|
||||
def selectaddress(self):
|
||||
"""copy address to clipboard when user clicks"""
|
||||
print('User clicked on ', self.rawaddress)
|
||||
Clipboard.put(self.rawaddress)
|
||||
|
||||
def transferfunds(self):
|
||||
"""initiate transfer of funds to new address"""
|
||||
transferfundsrpccall(self.input_amount.text, self.input_address.text, self.input_mixin.text)
|
||||
self.checkbalance()
|
||||
|
||||
|
||||
class KivyWalletApp(App):
|
||||
def build(self):
|
||||
return RootWidget()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
KivyWalletApp().run()
|
||||
Reference in New Issue
Block a user