Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
revoxhere
GitHub Repository: revoxhere/duino-coin
Path: blob/master/Legacy codes/Wallet.py
922 views
1
#!/usr/bin/env python3
2
##########################################
3
# Duino-Coin Tkinter GUI Wallet (v2.52)
4
# https://github.com/revoxhere/duino-coin
5
# Distributed under MIT license
6
# © Duino-Coin Community 2019-2022
7
##########################################
8
import sys
9
from base64 import b64decode, b64encode
10
from configparser import ConfigParser
11
from datetime import datetime
12
from json import loads
13
from json import loads as jsonloads
14
from locale import getdefaultlocale
15
from os import _exit, execl, mkdir
16
from os import name as osname
17
from os import path, system
18
from pathlib import Path
19
from sqlite3 import connect as sqlconn
20
import subprocess
21
from threading import Thread, Timer
22
from time import sleep, time
23
from tkinter import (END, LEFT, Button, E, Entry,
24
Frame, Label, Listbox, N, PhotoImage, S,
25
Scrollbar, StringVar, Tk, Toplevel, W, messagebox, ttk)
26
from tkinter.font import Font
27
from urllib.request import urlretrieve
28
from webbrowser import open_new_tab
29
30
from requests import get
31
32
# Version number
33
VERSION = 2.52
34
# Colors
35
BACKGROUND_COLOR = "#121212"
36
FONT_COLOR = "#fffdee"
37
FOREGROUND_COLOR = "#ff9f43"
38
FOREGROUND_COLOR_SECONDARY = "#fdcb6e"
39
# Minimum transaction amount to be saved
40
MIN_TRANSACTION_VALUE = 0.00000000001
41
# Minimum transaction amount to show a notification
42
MIN_TRANSACTION_VALUE_NOTIFY = 0.5
43
# Resources folder location
44
resources = "Wallet_" + str(VERSION) + "_resources/"
45
ENCRYPTION_ITERATIONS = 100_000
46
config = ConfigParser()
47
wrong_passphrase = False
48
global_balance = 0
49
oldbalance = 0
50
balance = 0
51
unpaid_balance = 0
52
profitCheck = 0
53
curr_bal = 0
54
WS_URI = "ws://server.duinocoin.com:15808"
55
56
57
def install(package):
58
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
59
execl(sys.executable, sys.executable, *sys.argv)
60
61
62
def get_duco_price():
63
global duco_fiat_value
64
jsonapi = get(
65
"https://raw.githubusercontent.com/"
66
+ "revoxhere/"
67
+ "duco-statistics/master/"
68
+ "api.json",
69
data=None)
70
if jsonapi.status_code == 200:
71
try:
72
content = jsonapi.content.decode()
73
contentjson = loads(content)
74
duco_fiat_value = round(float(contentjson["Duco price"]), 4)
75
except Exception:
76
duco_fiat_value = 0.003
77
else:
78
duco_fiat_value = 0.003
79
Timer(30, get_duco_price).start()
80
81
82
def title(title):
83
if osname == "nt":
84
system("title " + title)
85
else:
86
print("\33]0;" + title + "\a", end="")
87
sys.stdout.flush()
88
89
90
def _derive_key(
91
password: bytes,
92
salt: bytes,
93
iterations: int = ENCRYPTION_ITERATIONS) -> bytes:
94
kdf = PBKDF2HMAC(
95
algorithm=hashes.SHA256(),
96
length=32,
97
salt=salt,
98
iterations=ENCRYPTION_ITERATIONS,
99
backend=backend)
100
return b64e(kdf.derive(password))
101
102
103
def password_encrypt(
104
message: bytes,
105
password: str,
106
iterations: int = ENCRYPTION_ITERATIONS) -> bytes:
107
salt = secrets.token_bytes(16)
108
key = _derive_key(
109
password.encode(),
110
salt,
111
ENCRYPTION_ITERATIONS)
112
return b64e(
113
b"%b%b%b" % (
114
salt,
115
ENCRYPTION_ITERATIONS.to_bytes(4, "big"),
116
b64d(Fernet(key).encrypt(message))))
117
118
119
def password_decrypt(
120
token: bytes,
121
password: str) -> bytes:
122
decoded = b64d(token)
123
salt, ENCRYPTION_ITERATIONS, token = decoded[:16], decoded[16:20], b64e(
124
decoded[20:])
125
ENCRYPTION_ITERATIONS = int.from_bytes(ENCRYPTION_ITERATIONS, "big")
126
key = _derive_key(
127
password.encode(),
128
salt,
129
ENCRYPTION_ITERATIONS)
130
return Fernet(key).decrypt(token)
131
132
133
def get_string(string_name):
134
if string_name in lang_file[lang]:
135
return lang_file[lang][string_name]
136
elif string_name in lang_file["english"]:
137
return lang_file["english"][string_name]
138
else:
139
return "String not found: " + string_name
140
141
142
def openTos(handler):
143
open_new_tab("https://github.com/revoxhere/duino-coin#terms-of-usage")
144
145
146
def openGitHub(handler):
147
open_new_tab("https://github.com/revoxhere/duino-coin")
148
149
150
def openWebsite(handler):
151
open_new_tab("https://duinocoin.com")
152
153
154
def openExchange(handler):
155
open_new_tab("https://revoxhere.github.io/duco-exchange/")
156
157
158
def openDiscord(handler):
159
open_new_tab("https://discord.com/invite/kvBkccy")
160
161
162
def openTransaction(hashToOpen):
163
open_new_tab("https://explorer.duinocoin.com/?search="+str(hashToOpen))
164
165
166
class LoginFrame(Frame):
167
def __init__(self, master):
168
super().__init__(master)
169
messagebox.showerror(title="Warning",
170
message=("CLI and GUI wallets are being deprecated in favor of the Web Wallet. "
171
+ "This app may not run properly."))
172
173
master.title("Login")
174
master.resizable(False, False)
175
176
TEXT_FONT_BOLD = Font(size=12, weight="bold")
177
TEXT_FONT = Font(size=12, weight="normal")
178
179
self.duco = ImageTk.PhotoImage(Image.open(resources + "duco.png"))
180
self.duco.image = self.duco
181
self.ducoLabel = Label(
182
self, background=FOREGROUND_COLOR,
183
foreground=FONT_COLOR,
184
image=self.duco)
185
self.ducoLabel2 = Label(
186
self,
187
background=FOREGROUND_COLOR,
188
foreground=FONT_COLOR,
189
text=get_string("welcome_message"),
190
font=TEXT_FONT_BOLD)
191
self.spacer = Label(self)
192
193
self.label_username = Label(
194
self,
195
text=get_string("username"),
196
font=TEXT_FONT_BOLD,
197
background=BACKGROUND_COLOR,
198
foreground=FONT_COLOR,
199
padx=5)
200
self.label_password = Label(
201
self,
202
text=get_string("passwd"),
203
font=TEXT_FONT_BOLD,
204
background=BACKGROUND_COLOR,
205
foreground=FONT_COLOR,
206
padx=5)
207
self.entry_username = Entry(
208
self,
209
font=TEXT_FONT,
210
background=BACKGROUND_COLOR,
211
foreground=FOREGROUND_COLOR_SECONDARY)
212
self.entry_password = Entry(
213
self,
214
show="*",
215
font=TEXT_FONT,
216
background=BACKGROUND_COLOR,
217
foreground=FOREGROUND_COLOR_SECONDARY)
218
219
self.ducoLabel.grid(
220
row=0,
221
sticky="nswe",
222
pady=(5, 0),
223
padx=(5))
224
self.ducoLabel2.grid(
225
row=1,
226
sticky="nswe",
227
padx=(5))
228
self.label_username.grid(
229
row=4,
230
sticky=W,
231
pady=(5, 0))
232
self.entry_username.grid(
233
row=5,
234
sticky=N,
235
padx=(5))
236
self.label_password.grid(
237
row=6,
238
sticky=W)
239
self.entry_password.grid(
240
row=7,
241
sticky=N)
242
243
self.logbtn = Button(
244
self,
245
text=get_string("login"),
246
foreground=FOREGROUND_COLOR,
247
background=BACKGROUND_COLOR,
248
activebackground=BACKGROUND_COLOR,
249
command=self._login_btn_clicked,
250
font=TEXT_FONT_BOLD)
251
self.logbtn.grid(
252
columnspan=2,
253
sticky="nswe",
254
padx=(5),
255
pady=(5, 1))
256
257
self.regbtn = Button(
258
self,
259
text=get_string("register"),
260
foreground=FOREGROUND_COLOR,
261
background=BACKGROUND_COLOR,
262
activebackground=BACKGROUND_COLOR,
263
command=self._register_btn_clicked,
264
font=TEXT_FONT_BOLD)
265
self.regbtn.grid(
266
columnspan=2,
267
sticky="nswe",
268
padx=(5),
269
pady=(0, 5))
270
271
self.configure(background=BACKGROUND_COLOR)
272
self.master.bind(
273
"<Return>",
274
self._login_btn_clicked_bind)
275
self.pack()
276
277
def _login_btn_clicked_bind(self, event):
278
self._login_btn_clicked()
279
280
def _login_btn_clicked(self):
281
global username, password
282
username = self.entry_username.get()
283
password = self.entry_password.get()
284
285
if username and password:
286
soc = websocket.create_connection(WS_URI)
287
soc.recv().decode()
288
soc.send(bytes(
289
"LOGI,"
290
+ str(username)
291
+ ","
292
+ str(password),
293
encoding="utf8"))
294
response = soc.recv().decode()
295
response = response.rstrip("\n").split(",")
296
297
if response[0] == "OK":
298
passwordEnc = b64encode(bytes(password, encoding="utf8"))
299
with sqlconn(resources + "wallet.db") as con:
300
cur = con.cursor()
301
cur.execute(
302
"""INSERT INTO
303
UserData(username, password, useWrapper)
304
VALUES(?, ?, ?)""",
305
(username, passwordEnc, "False"))
306
con.commit()
307
root.destroy()
308
else:
309
messagebox.showerror(
310
title=get_string("login_error"),
311
message=response[1])
312
else:
313
messagebox.showerror(
314
title=get_string("login_error"),
315
message=get_string("fill_the_blanks_warning"))
316
317
def _registerprotocol(self):
318
emailS = email.get()
319
usernameS = username.get()
320
passwordS = password.get()
321
confpasswordS = confpassword.get()
322
323
if emailS and usernameS and passwordS and confpasswordS:
324
if passwordS == confpasswordS:
325
soc = websocket.create_connection(WS_URI)
326
soc.recv().decode()
327
soc.send(
328
bytes(
329
"REGI,"
330
+ str(usernameS)
331
+ ","
332
+ str(passwordS)
333
+ ","
334
+ str(emailS),
335
encoding="utf8"))
336
response = soc.recv().decode().rstrip("\n")
337
response = response.split(",")
338
339
if response[0] == "OK":
340
messagebox.showinfo(
341
title=get_string("registration_success"),
342
message=get_string("registration_success_msg"))
343
register.destroy()
344
execl(sys.executable, sys.executable, *sys.argv)
345
else:
346
messagebox.showerror(
347
title=get_string("register_error"),
348
message=response[1])
349
else:
350
messagebox.showerror(
351
title=get_string("register_error"),
352
message=get_string("error_passwd_dont_match"))
353
else:
354
messagebox.showerror(
355
title=get_string("register_error"),
356
message=get_string("fill_the_blanks_warning"))
357
358
def _register_btn_clicked(self):
359
global username, password, confpassword, email, register
360
root.destroy()
361
register = Tk()
362
register.title(get_string("register"))
363
register.resizable(False, False)
364
365
TEXT_FONT_BOLD = Font(
366
register,
367
size=12,
368
weight="bold")
369
TEXT_FONT = Font(
370
register,
371
size=12,
372
weight="normal")
373
374
tos_warning = get_string("register_tos_warning")
375
import textwrap
376
tos_warning = textwrap.dedent(tos_warning)
377
tos_warning = "\n".join(l for line in tos_warning.splitlines()
378
for l in textwrap.wrap(line, width=20))
379
380
duco = ImageTk.PhotoImage(Image.open(resources + "duco.png"))
381
duco.image = duco
382
ducoLabel = Label(
383
register,
384
background=FOREGROUND_COLOR,
385
foreground=FONT_COLOR,
386
image=duco)
387
ducoLabel.grid(
388
row=0,
389
padx=5,
390
pady=(5, 0),
391
sticky="nswe")
392
393
ducoLabel2 = Label(
394
register,
395
background=FOREGROUND_COLOR,
396
foreground=FONT_COLOR,
397
text=get_string("register_on_network"),
398
font=TEXT_FONT_BOLD)
399
ducoLabel2.grid(row=1,
400
padx=5,
401
sticky="nswe")
402
403
def colorLabelBlue(handler):
404
ducoLabel3.configure(foreground="#6c5ce7")
405
406
def colorLabelNormal(handler):
407
ducoLabel3.configure(foreground=FONT_COLOR)
408
409
ducoLabel3 = Label(
410
register,
411
background=FOREGROUND_COLOR,
412
foreground=FONT_COLOR,
413
text=tos_warning,
414
font=TEXT_FONT)
415
ducoLabel3.grid(
416
row=2,
417
padx=5,
418
sticky="nswe")
419
ducoLabel3.bind("<Button-1>", openTos)
420
ducoLabel3.bind("<Enter>", colorLabelBlue)
421
ducoLabel3.bind("<Leave>", colorLabelNormal)
422
423
Label(
424
register,
425
text=get_string("username").upper(),
426
background=BACKGROUND_COLOR,
427
foreground=FONT_COLOR,
428
font=TEXT_FONT_BOLD,
429
).grid(
430
row=3,
431
sticky=W,
432
padx=5,
433
pady=(5, 0))
434
username = Entry(
435
register,
436
font=TEXT_FONT,
437
background=BACKGROUND_COLOR,
438
foreground=FOREGROUND_COLOR_SECONDARY)
439
username.grid(
440
row=4,
441
padx=5)
442
443
Label(
444
register,
445
text=get_string("passwd").upper(),
446
background=BACKGROUND_COLOR,
447
foreground=FONT_COLOR,
448
font=TEXT_FONT_BOLD,
449
).grid(
450
row=5,
451
sticky=W,
452
padx=5)
453
password = Entry(
454
register,
455
show="*",
456
font=TEXT_FONT,
457
background=BACKGROUND_COLOR,
458
foreground=FOREGROUND_COLOR_SECONDARY)
459
password.grid(
460
row=6,
461
padx=5)
462
463
Label(
464
register,
465
text=get_string("confirm_passwd").upper(),
466
background=BACKGROUND_COLOR,
467
foreground=FONT_COLOR,
468
font=TEXT_FONT_BOLD,
469
).grid(
470
row=7,
471
sticky=W,
472
padx=5)
473
confpassword = Entry(
474
register,
475
show="*",
476
font=TEXT_FONT,
477
background=BACKGROUND_COLOR,
478
foreground=FOREGROUND_COLOR_SECONDARY)
479
confpassword.grid(
480
row=8,
481
padx=5)
482
483
Label(
484
register,
485
text=get_string("email").upper(),
486
background=BACKGROUND_COLOR,
487
foreground=FONT_COLOR,
488
font=TEXT_FONT_BOLD,
489
).grid(
490
row=9,
491
sticky=W,
492
padx=5)
493
email = Entry(
494
register,
495
font=TEXT_FONT,
496
background=BACKGROUND_COLOR,
497
foreground=FOREGROUND_COLOR_SECONDARY)
498
email.grid(
499
row=10,
500
padx=5)
501
502
self.logbtn = Button(
503
register,
504
text=get_string("register"),
505
activebackground=BACKGROUND_COLOR,
506
foreground=FOREGROUND_COLOR,
507
background=BACKGROUND_COLOR,
508
command=self._registerprotocol,
509
font=TEXT_FONT_BOLD)
510
self.logbtn.grid(
511
columnspan=2,
512
sticky="nswe",
513
padx=(5, 5),
514
pady=(5, 5))
515
register.configure(background=BACKGROUND_COLOR)
516
517
518
def loading_window():
519
global loading, status
520
loading = Tk()
521
loading.resizable(False, False)
522
loading.configure(background=BACKGROUND_COLOR)
523
loading.title(get_string("loading"))
524
try:
525
loading.iconphoto(True,
526
PhotoImage(file=resources + "duco_color.png"))
527
except Exception:
528
pass
529
TEXT_FONT = Font(loading,
530
size=10,
531
weight="bold")
532
TEXT_FONT_BOLD = Font(loading,
533
size=14,
534
weight="bold")
535
536
original = Image.open(resources + "duco_color.png")
537
resized = original.resize((128, 128), Image.ANTIALIAS)
538
github = ImageTk.PhotoImage(resized)
539
github.image = github
540
githubLabel = Label(loading,
541
image=github,
542
background=BACKGROUND_COLOR,
543
foreground=FONT_COLOR)
544
githubLabel.grid(row=0,
545
column=0,
546
sticky=N + S + E + W,
547
pady=(5, 0),
548
padx=(5))
549
550
Label(
551
loading,
552
text=get_string("duino_coin_wallet"),
553
font=TEXT_FONT_BOLD,
554
foreground=FOREGROUND_COLOR,
555
background=BACKGROUND_COLOR,
556
).grid(
557
row=1,
558
column=0,
559
sticky=S + W,
560
pady=(5, 0),
561
padx=5)
562
loading.update()
563
564
status = Label(
565
loading,
566
background=BACKGROUND_COLOR,
567
foreground=FONT_COLOR,
568
text=get_string("loading_database"),
569
font=TEXT_FONT)
570
status.grid(
571
row=2,
572
column=0,
573
sticky=S + W,
574
pady=(0, 5),
575
padx=5)
576
loading.update()
577
578
579
def transactions_window(handler):
580
transactionsWindow = Toplevel()
581
transactionsWindow.resizable(False, False)
582
transactionsWindow.title(get_string("wallet_transactions"))
583
transactionsWindow.transient([root])
584
transactionsWindow.configure(background=BACKGROUND_COLOR)
585
586
TEXT_FONT_BOLD_LARGE = Font(
587
transactionsWindow,
588
size=14,
589
weight="bold")
590
TEXT_FONT = Font(
591
transactionsWindow,
592
size=12,
593
weight="normal")
594
595
Label(
596
transactionsWindow,
597
text=get_string("transaction_list"),
598
font=TEXT_FONT_BOLD_LARGE,
599
background=BACKGROUND_COLOR,
600
foreground=FOREGROUND_COLOR,
601
).grid(row=0,
602
column=0,
603
columnspan=2,
604
sticky=S + W,
605
pady=(5, 0),
606
padx=5)
607
608
Label(
609
transactionsWindow,
610
text=get_string("transaction_list_notice"),
611
font=TEXT_FONT,
612
background=BACKGROUND_COLOR,
613
foreground=FONT_COLOR,
614
).grid(row=1,
615
column=0,
616
columnspan=2,
617
sticky=S + W,
618
pady=(5, 0),
619
padx=5)
620
621
listbox = Listbox(
622
transactionsWindow,
623
width="35",
624
background=BACKGROUND_COLOR,
625
foreground=FONT_COLOR)
626
listbox.grid(
627
row=2,
628
column=0,
629
sticky=S + W + N + E,
630
padx=(5, 0),
631
pady=(0, 5))
632
scrollbar = Scrollbar(transactionsWindow,
633
background=BACKGROUND_COLOR)
634
scrollbar.grid(
635
row=2,
636
column=1,
637
sticky=N + S,
638
padx=(0, 5),
639
pady=(0, 5))
640
641
for i in gtxl:
642
listbox.insert(END, gtxl[i]["Sender"] + " to " + gtxl[i]
643
["Recipient"] + ": " + str(gtxl[i]["Amount"]) + " DUCO")
644
645
def get_selection(event):
646
try:
647
selection = listbox.curselection()[0]
648
openTransaction(gtxl[str(selection)]["Hash"])
649
except IndexError:
650
pass
651
652
listbox.bind("<Button-1>", get_selection)
653
listbox.config(yscrollcommand=scrollbar.set, font=TEXT_FONT)
654
scrollbar.config(command=listbox.yview)
655
656
657
def currency_converter_calc():
658
fromcurrency = fromCurrencyInput.get(fromCurrencyInput.curselection())
659
tocurrency = toCurrencyInput.get(toCurrencyInput.curselection())
660
amount = amountInput.get()
661
662
# TODO
663
value = duco_fiat_value * float(amount)
664
665
result = get_string("result") + ": " + str(round(value, 6))
666
conversionresulttext.set(str(result))
667
calculatorWindow.update()
668
669
670
def currency_converter_window(handler):
671
global conversionresulttext
672
global fromCurrencyInput
673
global toCurrencyInput
674
global amountInput
675
global calculatorWindow
676
677
calculatorWindow = Toplevel()
678
calculatorWindow.resizable(False, False)
679
calculatorWindow.title(get_string("wallet_calculator"))
680
calculatorWindow.transient([root])
681
calculatorWindow.configure(background=BACKGROUND_COLOR)
682
683
TEXT_FONT_BOLD = Font(
684
calculatorWindow,
685
size=12,
686
weight="bold")
687
TEXT_FONT_BOLD_LARGE = Font(
688
calculatorWindow,
689
size=14,
690
weight="bold")
691
TEXT_FONT = Font(
692
calculatorWindow,
693
size=12,
694
weight="normal")
695
696
Label(
697
calculatorWindow,
698
text=get_string("currency_converter"),
699
font=TEXT_FONT_BOLD_LARGE,
700
foreground=FOREGROUND_COLOR,
701
background=BACKGROUND_COLOR,
702
).grid(row=0,
703
columnspan=2,
704
column=0,
705
sticky=S + W,
706
pady=5,
707
padx=5)
708
709
Label(
710
calculatorWindow,
711
text=get_string("from"),
712
font=TEXT_FONT_BOLD,
713
foreground=FOREGROUND_COLOR,
714
background=BACKGROUND_COLOR,
715
).grid(row=1,
716
column=0,
717
sticky=S + W,
718
padx=5)
719
fromCurrencyInput = Listbox(
720
calculatorWindow,
721
exportselection=False,
722
background=BACKGROUND_COLOR,
723
selectbackground=FOREGROUND_COLOR,
724
border="0",
725
font=TEXT_FONT,
726
foreground=FONT_COLOR,
727
width="20",
728
height="13",
729
)
730
fromCurrencyInput.grid(row=2,
731
column=0,
732
sticky=S + W,
733
padx=(5, 0))
734
fromCurrencyInput.insert(0, "DUCO")
735
736
vsb = Scrollbar(
737
calculatorWindow,
738
orient="vertical",
739
command=fromCurrencyInput.yview,
740
background=BACKGROUND_COLOR,
741
)
742
vsb.grid(row=2,
743
column=1,
744
sticky="ns",
745
padx=(0, 5))
746
fromCurrencyInput.configure(yscrollcommand=vsb.set)
747
748
fromCurrencyInput.select_set(0)
749
fromCurrencyInput.event_generate("<<ListboxSelect>>")
750
751
Label(
752
calculatorWindow,
753
text=get_string("to"),
754
font=TEXT_FONT_BOLD,
755
foreground=FOREGROUND_COLOR,
756
background=BACKGROUND_COLOR,
757
).grid(row=1,
758
column=3,
759
columnspan=2,
760
sticky=S + W,
761
padx=5)
762
toCurrencyInput = Listbox(
763
calculatorWindow,
764
exportselection=False,
765
background=BACKGROUND_COLOR,
766
selectbackground=FOREGROUND_COLOR,
767
border="0",
768
foreground=FONT_COLOR,
769
font=TEXT_FONT,
770
width="20",
771
height="13")
772
toCurrencyInput.grid(
773
row=2,
774
column=3,
775
sticky=S + W,
776
padx=(5, 0))
777
toCurrencyInput.insert(0, "USD")
778
779
vsb2 = Scrollbar(
780
calculatorWindow,
781
orient="vertical",
782
command=toCurrencyInput.yview,
783
background=BACKGROUND_COLOR,)
784
vsb2.grid(
785
row=2,
786
column=4,
787
sticky="ns",
788
padx=(0, 5))
789
toCurrencyInput.configure(yscrollcommand=vsb2.set)
790
791
toCurrencyInput.select_set(0)
792
toCurrencyInput.event_generate("<<ListboxSelect>>")
793
794
Label(
795
calculatorWindow,
796
text=get_string("input_amount"),
797
font=TEXT_FONT_BOLD,
798
foreground=FOREGROUND_COLOR,
799
background=BACKGROUND_COLOR,
800
).grid(row=3,
801
columnspan=2,
802
column=0,
803
sticky=S + W,
804
padx=5)
805
806
def clear_ccamount_placeholder(self):
807
amountInput.delete("0", "100")
808
809
amountInput = Entry(
810
calculatorWindow,
811
foreground=FOREGROUND_COLOR_SECONDARY,
812
border="0",
813
font=TEXT_FONT,
814
background=BACKGROUND_COLOR,)
815
amountInput.grid(
816
row=4,
817
column=0,
818
sticky=N + S + W + E,
819
padx=5,
820
columnspan=2,
821
pady=(0, 5))
822
amountInput.insert("0", str(global_balance))
823
amountInput.bind("<FocusIn>", clear_ccamount_placeholder)
824
825
Button(
826
calculatorWindow,
827
text=get_string("calculate"),
828
font=TEXT_FONT_BOLD,
829
foreground=FOREGROUND_COLOR,
830
activebackground=BACKGROUND_COLOR,
831
background=BACKGROUND_COLOR,
832
command=currency_converter_calc,
833
).grid(row=3,
834
columnspan=2,
835
column=2,
836
sticky=N + S + W + E,
837
pady=(5, 0),
838
padx=5)
839
840
conversionresulttext = StringVar(calculatorWindow)
841
conversionresulttext.set(get_string("result") + ": 0.0")
842
conversionresultLabel = Label(
843
calculatorWindow,
844
textvariable=conversionresulttext,
845
font=TEXT_FONT_BOLD,
846
background=BACKGROUND_COLOR,
847
foreground=FONT_COLOR,)
848
conversionresultLabel.grid(
849
row=4,
850
columnspan=2,
851
column=2,
852
pady=(0, 5))
853
854
calculatorWindow.mainloop()
855
856
857
def statistics_window(handler):
858
statsApi = get(
859
"https://server.duinocoin.com"
860
+ "/api.json",
861
data=None)
862
if statsApi.status_code == 200: # Check for reponse
863
statsApi = statsApi.json()
864
865
miner_api = get(
866
"https://server.duinocoin.com"
867
+ "/miners.json",
868
data=None)
869
if miner_api.status_code == 200: # Check for reponse
870
miner_api = miner_api.json()
871
872
statsWindow = Toplevel()
873
statsWindow.resizable(False, False)
874
statsWindow.title(get_string("statistics_title"))
875
statsWindow.transient([root])
876
statsWindow.configure(background=BACKGROUND_COLOR)
877
878
TEXT_FONT_BOLD_LARGE = Font(
879
statsWindow,
880
size=14,
881
weight="bold")
882
TEXT_FONT = Font(
883
statsWindow,
884
size=12,
885
weight="normal")
886
887
Active_workers_listbox = Listbox(
888
statsWindow,
889
exportselection=False,
890
background=BACKGROUND_COLOR,
891
foreground=FONT_COLOR,
892
border="0",
893
font=TEXT_FONT,
894
width="65",
895
height="8",)
896
Active_workers_listbox.grid(
897
row=1,
898
columnspan=2,
899
sticky=N + E + S + W,
900
pady=(0, 5),
901
padx=5)
902
i = 0
903
totalHashrate = 0
904
905
for threadid in miner_api:
906
if username in miner_api[threadid]["User"]:
907
rigId = miner_api[threadid]["Identifier"]
908
if rigId == "None":
909
rigId = ""
910
else:
911
rigId += ": "
912
software = miner_api[threadid]["Software"]
913
hashrate = str(round(miner_api[threadid]["Hashrate"], 2))
914
totalHashrate += float(hashrate)
915
difficulty = str(miner_api[threadid]["Diff"])
916
shares = (
917
str(miner_api[threadid]["Accepted"])
918
+ "/"
919
+ str(
920
miner_api[threadid]["Accepted"]
921
+ miner_api[threadid]["Rejected"]))
922
923
Active_workers_listbox.insert(
924
i,
925
"#"
926
+ str(i + 1)
927
+ ": "
928
+ rigId
929
+ software
930
+ " "
931
+ str(round(float(hashrate) / 1000, 2))
932
+ " kH/s @ diff "
933
+ difficulty
934
+ ", "
935
+ shares)
936
i += 1
937
if i == 0:
938
Active_workers_listbox.insert(
939
i, get_string("statistics_miner_warning"))
940
941
totalHashrateString = str(int(totalHashrate)) + " H/s"
942
if totalHashrate > 1000000000:
943
totalHashrateString = str(
944
round(totalHashrate / 1000000000, 2)) + " GH/s"
945
elif totalHashrate > 1000000:
946
totalHashrateString = str(round(totalHashrate / 1000000, 2)) + " MH/s"
947
elif totalHashrate > 1000:
948
totalHashrateString = str(round(totalHashrate / 1000, 2)) + " kH/s"
949
950
Active_workers_listbox.configure(height=i)
951
Active_workers_listbox.select_set(32)
952
Active_workers_listbox.event_generate("<<ListboxSelect>>")
953
954
Label(
955
statsWindow,
956
text=get_string("your_miners") + " - " + totalHashrateString,
957
font=TEXT_FONT_BOLD_LARGE,
958
foreground=FOREGROUND_COLOR,
959
background=BACKGROUND_COLOR,
960
).grid(
961
row=0,
962
column=0,
963
columnspan=2,
964
sticky=S + W,
965
pady=5,
966
padx=5)
967
968
Label(
969
statsWindow,
970
text=get_string("richlist"),
971
font=TEXT_FONT_BOLD_LARGE,
972
foreground=FOREGROUND_COLOR,
973
background=BACKGROUND_COLOR,
974
).grid(
975
row=2,
976
column=0,
977
sticky=S + W,
978
pady=5,
979
padx=5)
980
Top_10_listbox = Listbox(
981
statsWindow,
982
exportselection=False,
983
border="0",
984
font=TEXT_FONT,
985
width="30",
986
height="10",
987
background=BACKGROUND_COLOR,
988
foreground=FONT_COLOR)
989
Top_10_listbox.grid(
990
row=3,
991
column=0,
992
rowspan=10,
993
sticky=N + E + S + W,
994
pady=(0, 5),
995
padx=5)
996
997
num = 0
998
for i in statsApi["Top 10 richest miners"]:
999
Top_10_listbox.insert(num, i)
1000
num += 1
1001
1002
Top_10_listbox.select_set(32)
1003
Top_10_listbox.event_generate("<<ListboxSelect>>")
1004
1005
Label(
1006
statsWindow,
1007
text=get_string("network_info"),
1008
font=TEXT_FONT_BOLD_LARGE,
1009
foreground=FOREGROUND_COLOR,
1010
background=BACKGROUND_COLOR,
1011
).grid(row=2,
1012
column=1,
1013
sticky=S + W,
1014
padx=5,
1015
pady=5)
1016
Label(
1017
statsWindow,
1018
text=get_string("difficulty")
1019
+ ": "
1020
+ str(statsApi["Current difficulty"]),
1021
font=TEXT_FONT,
1022
background=BACKGROUND_COLOR,
1023
foreground=FONT_COLOR,
1024
).grid(row=3,
1025
column=1,
1026
sticky=S + W,
1027
padx=5)
1028
Label(
1029
statsWindow,
1030
text=get_string("mined_blocks")
1031
+ ": "
1032
+ str(statsApi["Mined blocks"]),
1033
font=TEXT_FONT,
1034
background=BACKGROUND_COLOR,
1035
foreground=FONT_COLOR,
1036
).grid(row=4,
1037
column=1,
1038
sticky=S + W,
1039
padx=5)
1040
Label(
1041
statsWindow,
1042
text=get_string("network_hashrate")
1043
+ ": "
1044
+ str(statsApi["Pool hashrate"]),
1045
font=TEXT_FONT,
1046
background=BACKGROUND_COLOR,
1047
foreground=FONT_COLOR,
1048
).grid(row=5,
1049
column=1,
1050
sticky=S + W,
1051
padx=5)
1052
Label(
1053
statsWindow,
1054
text=get_string("active_miners")
1055
+ ": "
1056
+ str(len(statsApi["Miners"])),
1057
font=TEXT_FONT,
1058
background=BACKGROUND_COLOR,
1059
foreground=FONT_COLOR,
1060
).grid(row=6,
1061
column=1,
1062
sticky=S + W,
1063
padx=5)
1064
Label(
1065
statsWindow,
1066
text="1 DUCO "
1067
+ get_string("estimated_price")
1068
+ ": $"
1069
+ str(statsApi["Duco price"]),
1070
font=TEXT_FONT,
1071
background=BACKGROUND_COLOR,
1072
foreground=FONT_COLOR,
1073
).grid(row=7,
1074
column=1,
1075
sticky=S + W,
1076
padx=5)
1077
Label(
1078
statsWindow,
1079
text=get_string("registered_users")
1080
+ ": "
1081
+ str(statsApi["Registered users"]),
1082
font=TEXT_FONT,
1083
background=BACKGROUND_COLOR,
1084
foreground=FONT_COLOR,
1085
).grid(row=8,
1086
column=1,
1087
sticky=S + W,
1088
padx=5)
1089
Label(
1090
statsWindow,
1091
text=get_string("mined_duco")
1092
+ ": "
1093
+ str(statsApi["All-time mined DUCO"])
1094
+ " ᕲ",
1095
font=TEXT_FONT,
1096
background=BACKGROUND_COLOR,
1097
foreground=FONT_COLOR,
1098
).grid(row=9,
1099
column=1,
1100
sticky=S + W,
1101
padx=5)
1102
1103
statsWindow.mainloop()
1104
1105
1106
def wrapper_window(handler):
1107
def Wrap():
1108
amount = amountWrap.get()
1109
print("Got amount:", amount)
1110
print("pub key:", pub_key)
1111
soc = websocket.create_connection(WS_URI)
1112
soc.recv().decode()
1113
try:
1114
float(amount)
1115
except Exception:
1116
pass
1117
else:
1118
soc.send(bytes(
1119
"LOGI,"
1120
+ str(username)
1121
+ ","
1122
+ str(password),
1123
encoding="utf8"))
1124
_ = soc.recv().decode()
1125
soc.send(
1126
bytes(
1127
"WRAP,"
1128
+ str(amount)
1129
+ ","
1130
+ str(pub_key)
1131
+ str(",placeholder"),
1132
encoding="utf8"))
1133
soc.close()
1134
sleep(2)
1135
wrapperWindow.quit()
1136
1137
try:
1138
pubkeyfile = open(str(resources + "DUCOPubKey.pub"), "r")
1139
except Exception:
1140
messagebox.showerror(
1141
title=get_string("wrapper_error_title"),
1142
message=get_string("wrapper_error"))
1143
else:
1144
if TRONPY_ENABLED:
1145
pub_key = pubkeyfile.read()
1146
pubkeyfile.close()
1147
1148
wrapperWindow = Toplevel()
1149
wrapperWindow.resizable(False, False)
1150
wrapperWindow.title(get_string("wrapper_title"))
1151
wrapperWindow.transient([root])
1152
1153
askWrapAmount = Label(
1154
wrapperWindow,
1155
text=get_string("wrapper_amount_to_wrap") + ":")
1156
askWrapAmount.grid(row=0,
1157
column=0,
1158
sticky=N + W)
1159
amountWrap = Entry(wrapperWindow,
1160
border="0",
1161
font=Font(size=15))
1162
amountWrap.grid(row=1,
1163
column=0,
1164
sticky=N + W)
1165
wrapButton = Button(wrapperWindow,
1166
text="Wrap",
1167
command=Wrap)
1168
wrapButton.grid(row=2,
1169
column=0,
1170
sticky=N + W)
1171
else:
1172
messagebox.showerror(
1173
title=get_string("wrapper_error_title"),
1174
message=get_string("wrapper_error_tronpy"))
1175
1176
1177
def unwrapper_window(handler):
1178
def UnWrap():
1179
pubkeyfile = open(str(resources + "DUCOPubKey.pub"), "r")
1180
pub_key = pubkeyfile.read()
1181
pubkeyfile.close()
1182
1183
passphrase = passphraseEntry.get()
1184
privkeyfile = open(str(resources + "DUCOPrivKey.encrypt"), "r")
1185
privKeyEnc = privkeyfile.read()
1186
privkeyfile.close()
1187
1188
try:
1189
priv_key = password_decrypt(privKeyEnc, passphrase).decode()
1190
use_wrapper = True
1191
except InvalidToken:
1192
print(get_string("invalid_passphrase"))
1193
use_wrapper = False
1194
1195
amount = amountUnWrap.get()
1196
print("Got amount:", amount)
1197
soc = websocket.create_connection(WS_URI)
1198
soc.recv().decode()
1199
try:
1200
float(amount)
1201
except Exception:
1202
pass
1203
else:
1204
soc.send(bytes(
1205
"LOGI,"
1206
+ str(username)
1207
+ ","
1208
+ str(password), encoding="utf8"))
1209
_ = soc.recv().decode()
1210
if use_wrapper:
1211
pendingvalues = wduco.functions.pendingWithdrawals(
1212
pub_key, username)
1213
# transaction wasn't initiated, but variable should be declared
1214
txn_success = False
1215
try:
1216
amount = float(amount)
1217
except ValueError:
1218
print("Value should be numeric - aborting")
1219
else:
1220
if int(float(amount) * 10 ** 6) >= pendingvalues:
1221
toInit = int(float(amount) * 10 ** 6) - pendingvalues
1222
else:
1223
toInit = amount * 10 ** 6
1224
if toInit > 0:
1225
txn = (
1226
wduco.functions.initiateWithdraw(username, toInit)
1227
.with_owner(pub_key)
1228
.fee_limit(5_000_000)
1229
.build()
1230
.sign(PrivateKey(bytes.fromhex(priv_key))))
1231
txn = txn.broadcast()
1232
txnfeedback = txn.result()
1233
if txnfeedback:
1234
txn_success = True
1235
else:
1236
txn_success = False
1237
if txn_success or amount <= pendingvalues:
1238
soc.send(
1239
bytes(
1240
"UNWRAP,"
1241
+ str(amount)
1242
+ ","
1243
+ str(pub_key)
1244
+ str(",placeholder"),
1245
encoding="utf8"))
1246
1247
soc.close()
1248
sleep(2)
1249
unWrapperWindow.quit()
1250
1251
try:
1252
pubkeyfile = open(str(resources + "DUCOPubKey.pub"), "r")
1253
pubkeyfile.read()
1254
pubkeyfile.close()
1255
except Exception:
1256
messagebox.showerror(
1257
title=get_string("wrapper_error_title"),
1258
message=get_string("wrapper_error"))
1259
else:
1260
if TRONPY_ENABLED:
1261
unWrapperWindow = Toplevel()
1262
unWrapperWindow.resizable(False, False)
1263
unWrapperWindow.title(get_string("unwrapper_title"))
1264
unWrapperWindow.transient([root])
1265
unWrapperWindow.configure()
1266
askAmount = Label(
1267
unWrapperWindow,
1268
text=get_string("unwrap_amount"))
1269
askAmount.grid(row=1,
1270
column=0,
1271
sticky=N + W)
1272
1273
amountUnWrap = Entry(
1274
unWrapperWindow,
1275
border="0",
1276
font=Font(size=15))
1277
amountUnWrap.grid(row=2,
1278
column=0,
1279
sticky=N + W)
1280
1281
askPassphrase = Label(
1282
unWrapperWindow,
1283
text=get_string("ask_passphrase"))
1284
askPassphrase.grid(row=4,
1285
column=0,
1286
sticky=N + W)
1287
1288
passphraseEntry = Entry(
1289
unWrapperWindow,
1290
border="0",
1291
font=Font(size=15))
1292
passphraseEntry.grid(
1293
row=5,
1294
column=0,
1295
sticky=N + W)
1296
1297
wrapButton = Button(
1298
unWrapperWindow,
1299
text=get_string("unwrap_duco"),
1300
command=UnWrap)
1301
wrapButton.grid(
1302
row=7,
1303
column=0,
1304
sticky=N + W)
1305
else:
1306
messagebox.showerror(
1307
title=get_string("wrapper_error"),
1308
message=get_string("wrapper_error_tronpy"))
1309
1310
1311
def settings_window(handler):
1312
def _wrapperconf():
1313
if TRONPY_ENABLED:
1314
privkey_input = StringVar()
1315
passphrase_input = StringVar()
1316
wrapconfWindow = Toplevel()
1317
wrapconfWindow.resizable(False, False)
1318
wrapconfWindow.title(get_string("wrapper_title"))
1319
wrapconfWindow.transient([root])
1320
wrapconfWindow.configure()
1321
1322
def setwrapper():
1323
if privkey_input and passphrase_input:
1324
priv_key = privkey_entry.get()
1325
print("Got priv key:", priv_key)
1326
passphrase = passphrase_entry.get()
1327
print("Got passphrase:", passphrase)
1328
try:
1329
pub_key = PrivateKey(
1330
bytes.fromhex(priv_key)
1331
).public_key.to_base58check_address()
1332
except Exception:
1333
pass
1334
else:
1335
print("Saving data")
1336
1337
privkeyfile = open(
1338
str(resources + "DUCOPrivKey.encrypt"), "w")
1339
privkeyfile.write(
1340
str(password_encrypt(
1341
priv_key.encode(), passphrase
1342
).decode()))
1343
privkeyfile.close()
1344
1345
pubkeyfile = open(
1346
str(resources + "DUCOPubKey.pub"), "w")
1347
pubkeyfile.write(pub_key)
1348
pubkeyfile.close()
1349
1350
Label(wrapconfWindow, text=get_string(
1351
"wrapper_success")).pack()
1352
wrapconfWindow.quit()
1353
1354
title = Label(
1355
wrapconfWindow,
1356
text=get_string("wrapper_config_title"),
1357
font=Font(size=20))
1358
title.grid(row=0,
1359
column=0,
1360
sticky=N + W,
1361
padx=5)
1362
1363
askprivkey = Label(
1364
wrapconfWindow,
1365
text=get_string("ask_private_key"))
1366
askprivkey.grid(row=1,
1367
column=0,
1368
sticky=N + W)
1369
1370
privkey_entry = Entry(
1371
wrapconfWindow,
1372
font=TEXT_FONT,
1373
textvariable=privkey_input)
1374
privkey_entry.grid(row=2,
1375
column=0,
1376
sticky=N + W)
1377
1378
askpassphrase = Label(wrapconfWindow,
1379
text=get_string("passphrase"))
1380
askpassphrase.grid(row=3,
1381
column=0,
1382
sticky=N + W)
1383
1384
passphrase_entry = Entry(
1385
wrapconfWindow,
1386
font=TEXT_FONT,
1387
textvariable=passphrase_input)
1388
passphrase_entry.grid(row=4,
1389
column=0,
1390
sticky=N + W)
1391
1392
wrapConfigButton = Button(
1393
wrapconfWindow,
1394
text=get_string("configure_wrapper_lowercase"),
1395
command=setwrapper)
1396
wrapConfigButton.grid(row=5,
1397
column=0,
1398
sticky=N + W)
1399
1400
wrapconfWindow.mainloop()
1401
1402
else:
1403
messagebox.showerror(
1404
title=get_string("wrapper_error"),
1405
message=get_string("wrapper_error_tronpy"))
1406
1407
def _logout():
1408
try:
1409
with sqlconn(resources + "wallet.db") as con:
1410
cur = con.cursor()
1411
cur.execute("DELETE FROM UserData")
1412
con.commit()
1413
except Exception as e:
1414
print(e)
1415
try:
1416
execl(sys.executable, sys.executable, *sys.argv)
1417
except Exception as e:
1418
print(e)
1419
1420
def _cleartrs():
1421
with sqlconn(resources + "wallet.db") as con:
1422
cur = con.cursor()
1423
cur.execute("DELETE FROM transactions")
1424
con.commit()
1425
1426
def _chgpass():
1427
def _changepassprotocol():
1428
oldpasswordS = oldpassword.get()
1429
newpasswordS = newpassword.get()
1430
confpasswordS = confpassword.get()
1431
1432
if oldpasswordS != newpasswordS:
1433
if oldpasswordS and newpasswordS and confpasswordS:
1434
if newpasswordS == confpasswordS:
1435
soc = websocket.create_connection(WS_URI)
1436
soc.recv().decode()
1437
soc.send(
1438
bytes(
1439
"LOGI,"
1440
+ str(username)
1441
+ ","
1442
+ str(password), encoding="utf8"))
1443
soc.recv().decode()
1444
soc.send(
1445
bytes(
1446
"CHGP,"
1447
+ str(oldpasswordS)
1448
+ ","
1449
+ str(newpasswordS),
1450
encoding="utf8"))
1451
response = soc.recv().decode().rstrip("\n").split(",")
1452
soc.close()
1453
1454
if not "OK" in response[0]:
1455
messagebox.showerror(
1456
title=get_string("change_passwd_error"),
1457
message=response[1])
1458
else:
1459
messagebox.showinfo(
1460
title=get_string("change_passwd_ok"),
1461
message=response[1])
1462
try:
1463
try:
1464
with sqlconn(
1465
resources + "wallet.db"
1466
) as con:
1467
cur = con.cursor()
1468
cur.execute("DELETE FROM UserData")
1469
con.commit()
1470
except Exception as e:
1471
print(e)
1472
except FileNotFoundError:
1473
pass
1474
execl(sys.executable, sys.executable, *sys.argv)
1475
else:
1476
messagebox.showerror(
1477
title=get_string("change_passwd_error"),
1478
message=get_string("error_passwd_dont_match"))
1479
else:
1480
messagebox.showerror(
1481
title=get_string("change_passwd_error"),
1482
message=get_string("fill_the_blanks_warning"))
1483
else:
1484
messagebox.showerror(
1485
title=get_string("change_passwd_error"),
1486
message=get_string("same_passwd_error"))
1487
1488
settingsWindow.destroy()
1489
changepassWindow = Toplevel()
1490
changepassWindow.title(get_string("change_passwd_lowercase"))
1491
changepassWindow.resizable(False, False)
1492
changepassWindow.transient([root])
1493
changepassWindow.configure(background=BACKGROUND_COLOR)
1494
1495
TEXT_FONT_BOLD = Font(changepassWindow, size=12, weight="bold")
1496
TEXT_FONT = Font(changepassWindow, size=12, weight="normal")
1497
1498
Label(
1499
changepassWindow,
1500
text=get_string("old_passwd"),
1501
font=TEXT_FONT_BOLD,
1502
background=BACKGROUND_COLOR,
1503
foreground=FONT_COLOR,
1504
).grid(row=0,
1505
sticky=W,
1506
padx=5)
1507
oldpassword = Entry(
1508
changepassWindow,
1509
show="*",
1510
font=TEXT_FONT,
1511
foreground=FOREGROUND_COLOR_SECONDARY,
1512
background=BACKGROUND_COLOR)
1513
oldpassword.grid(row=1,
1514
sticky="nswe",
1515
padx=5)
1516
1517
Label(
1518
changepassWindow,
1519
text=get_string("new_passwd"),
1520
font=TEXT_FONT_BOLD,
1521
background=BACKGROUND_COLOR,
1522
foreground=FONT_COLOR,
1523
).grid(row=2,
1524
sticky=W,
1525
padx=5)
1526
newpassword = Entry(
1527
changepassWindow,
1528
show="*",
1529
font=TEXT_FONT,
1530
foreground=FOREGROUND_COLOR_SECONDARY,
1531
background=BACKGROUND_COLOR)
1532
newpassword.grid(row=3,
1533
sticky="nswe",
1534
padx=5)
1535
1536
Label(
1537
changepassWindow,
1538
text=get_string("confirm_new_passwd"),
1539
font=TEXT_FONT_BOLD,
1540
background=BACKGROUND_COLOR,
1541
foreground=FONT_COLOR,
1542
).grid(row=4,
1543
sticky=W,
1544
padx=5)
1545
confpassword = Entry(
1546
changepassWindow,
1547
show="*",
1548
font=TEXT_FONT,
1549
foreground=FOREGROUND_COLOR_SECONDARY,
1550
background=BACKGROUND_COLOR)
1551
confpassword.grid(row=5,
1552
sticky="nswe",
1553
padx=5)
1554
1555
chgpbtn = Button(
1556
changepassWindow,
1557
text=get_string("change_passwd"),
1558
command=_changepassprotocol,
1559
foreground=FOREGROUND_COLOR,
1560
font=TEXT_FONT_BOLD,
1561
background=BACKGROUND_COLOR,
1562
activebackground=BACKGROUND_COLOR)
1563
chgpbtn.grid(columnspan=2,
1564
sticky="nswe",
1565
pady=5,
1566
padx=5)
1567
1568
settingsWindow = Toplevel()
1569
settingsWindow.resizable(False, False)
1570
settingsWindow.title(get_string("settings_title"))
1571
settingsWindow.transient([root])
1572
settingsWindow.configure(background=BACKGROUND_COLOR)
1573
TEXT_FONT = Font(
1574
settingsWindow,
1575
size=12,
1576
weight="normal")
1577
TEXT_FONT_BOLD_LARGE = Font(
1578
settingsWindow,
1579
size=12,
1580
weight="bold")
1581
1582
Label(
1583
settingsWindow,
1584
text=get_string("uppercase_settings"),
1585
font=TEXT_FONT_BOLD_LARGE,
1586
foreground=FOREGROUND_COLOR,
1587
background=BACKGROUND_COLOR,
1588
).grid(row=0,
1589
column=0,
1590
columnspan=4,
1591
sticky=S + W,
1592
pady=(5, 5),
1593
padx=(5, 0))
1594
1595
logoutbtn = Button(
1596
settingsWindow,
1597
text=get_string("logout"),
1598
command=_logout,
1599
font=TEXT_FONT,
1600
background=BACKGROUND_COLOR,
1601
activebackground=BACKGROUND_COLOR,
1602
foreground=FONT_COLOR)
1603
logoutbtn.grid(row=1,
1604
column=0,
1605
columnspan=4,
1606
sticky="nswe",
1607
padx=5)
1608
1609
chgpassbtn = Button(
1610
settingsWindow,
1611
text=get_string("change_passwd"),
1612
command=_chgpass,
1613
font=TEXT_FONT,
1614
background=BACKGROUND_COLOR,
1615
activebackground=BACKGROUND_COLOR,
1616
foreground=FONT_COLOR)
1617
chgpassbtn.grid(row=2,
1618
column=0,
1619
columnspan=4,
1620
sticky="nswe",
1621
padx=5)
1622
1623
wrapperconfbtn = Button(
1624
settingsWindow,
1625
text=get_string("configure_wrapper"),
1626
command=_wrapperconf,
1627
font=TEXT_FONT,
1628
background=BACKGROUND_COLOR,
1629
activebackground=BACKGROUND_COLOR,
1630
foreground=FONT_COLOR)
1631
wrapperconfbtn.grid(row=3,
1632
column=0,
1633
columnspan=4,
1634
sticky="nswe",
1635
padx=5)
1636
1637
cleartransbtn = Button(
1638
settingsWindow,
1639
text=get_string("clear_transactions"),
1640
command=_cleartrs,
1641
font=TEXT_FONT,
1642
background=BACKGROUND_COLOR,
1643
activebackground=BACKGROUND_COLOR,
1644
foreground=FONT_COLOR)
1645
cleartransbtn.grid(row=4,
1646
column=0,
1647
columnspan=4,
1648
sticky="nswe",
1649
padx=5)
1650
1651
separator = ttk.Separator(settingsWindow, orient="horizontal")
1652
separator.grid(
1653
row=5,
1654
column=0,
1655
columnspan=4,
1656
sticky=N + S + E + W,
1657
padx=(5, 5),
1658
pady=5)
1659
1660
Label(
1661
settingsWindow,
1662
text=get_string("logged_in_as")
1663
+ ": "
1664
+ str(username),
1665
font=TEXT_FONT,
1666
background=BACKGROUND_COLOR,
1667
foreground=FONT_COLOR,
1668
).grid(
1669
row=6,
1670
column=0,
1671
columnspan=4,
1672
padx=5,
1673
sticky=S + W)
1674
Label(
1675
settingsWindow,
1676
text=get_string("wallet_version")
1677
+ ": "
1678
+ str(VERSION),
1679
font=TEXT_FONT,
1680
background=BACKGROUND_COLOR,
1681
foreground=FONT_COLOR,
1682
).grid(
1683
row=7,
1684
column=0,
1685
columnspan=4,
1686
padx=5,
1687
sticky=S + W)
1688
Label(
1689
settingsWindow,
1690
text=get_string("translation_author_message")
1691
+ " "
1692
+ get_string("translation_author"),
1693
font=TEXT_FONT,
1694
background=BACKGROUND_COLOR,
1695
foreground=FONT_COLOR,
1696
).grid(
1697
row=8,
1698
column=0,
1699
columnspan=4,
1700
padx=5,
1701
sticky=S + W)
1702
Label(
1703
settingsWindow,
1704
text=get_string("config_dev_warning"),
1705
font=TEXT_FONT,
1706
background=BACKGROUND_COLOR,
1707
foreground=FONT_COLOR,
1708
).grid(
1709
row=9,
1710
column=0,
1711
columnspan=4,
1712
padx=5,
1713
sticky=S + W)
1714
1715
separator = ttk.Separator(settingsWindow, orient="horizontal")
1716
separator.grid(
1717
row=10,
1718
column=0,
1719
columnspan=4,
1720
sticky=N + S + E + W,
1721
padx=(5, 5),
1722
pady=5)
1723
1724
original = Image.open(resources + "duco.png")
1725
resized = original.resize((48, 48), Image.ANTIALIAS)
1726
website = ImageTk.PhotoImage(resized)
1727
website.image = website
1728
websiteLabel = Label(
1729
settingsWindow,
1730
image=website,
1731
background=BACKGROUND_COLOR,
1732
foreground=FONT_COLOR)
1733
websiteLabel.grid(
1734
row=11,
1735
column=0,
1736
sticky=N + S + E + W,
1737
padx=(5, 0),
1738
pady=(0, 5))
1739
websiteLabel.bind("<Button-1>", openWebsite)
1740
1741
original = Image.open(resources + "github.png")
1742
resized = original.resize((48, 48), Image.ANTIALIAS)
1743
github = ImageTk.PhotoImage(resized)
1744
github.image = github
1745
githubLabel = Label(
1746
settingsWindow,
1747
image=github,
1748
background=BACKGROUND_COLOR,
1749
foreground=FONT_COLOR)
1750
githubLabel.grid(
1751
row=11,
1752
column=1,
1753
sticky=N + S + E + W,
1754
pady=(0, 5))
1755
githubLabel.bind("<Button-1>", openGitHub)
1756
1757
original = Image.open(resources + "exchange.png")
1758
resized = original.resize((48, 48), Image.ANTIALIAS)
1759
exchange = ImageTk.PhotoImage(resized)
1760
exchange.image = exchange
1761
exchangeLabel = Label(
1762
settingsWindow,
1763
image=exchange,
1764
background=BACKGROUND_COLOR,
1765
foreground=FONT_COLOR)
1766
exchangeLabel.grid(
1767
row=11,
1768
column=2,
1769
sticky=N + S + E + W,
1770
pady=(0, 5))
1771
exchangeLabel.bind("<Button-1>", openExchange)
1772
1773
original = Image.open(resources + "discord.png")
1774
resized = original.resize((48, 48), Image.ANTIALIAS)
1775
discord = ImageTk.PhotoImage(resized)
1776
discord.image = discord
1777
discordLabel = Label(
1778
settingsWindow,
1779
image=discord,
1780
background=BACKGROUND_COLOR,
1781
foreground=FONT_COLOR)
1782
discordLabel.grid(
1783
row=11,
1784
column=3,
1785
sticky=N + S + E + W,
1786
padx=(0, 5),
1787
pady=(0, 5))
1788
discordLabel.bind("<Button-1>", openDiscord)
1789
1790
1791
def get_balance():
1792
global oldbalance
1793
global balance
1794
global unpaid_balance
1795
global global_balance
1796
global gtxl
1797
try:
1798
soc = websocket.create_connection(WS_URI)
1799
soc.recv().decode()
1800
soc.send(bytes(
1801
"LOGI,"
1802
+ str(username)
1803
+ ","
1804
+ str(password), encoding="utf8"))
1805
_ = soc.recv().decode()
1806
soc.send(bytes(
1807
"BALA",
1808
encoding="utf8"))
1809
oldbalance = balance
1810
balance = float(soc.recv().decode().rstrip("\n"))
1811
global_balance = round(float(balance), 8)
1812
1813
try:
1814
gtxl = {}
1815
soc.send(bytes(
1816
"GTXL," + str(username) + ",7",
1817
encoding="utf8"))
1818
gtxl = str(soc.recv().decode().rstrip(
1819
"\n").replace("\'", "\""))
1820
gtxl = jsonloads(gtxl)
1821
except Exception as e:
1822
print("Error getting transaction list: " + str(e))
1823
1824
if oldbalance != balance:
1825
difference = float(balance) - float(oldbalance)
1826
dif_with_unpaid = (
1827
float(balance) - float(oldbalance)) + unpaid_balance
1828
if float(balance) != float(difference):
1829
if (dif_with_unpaid >= MIN_TRANSACTION_VALUE
1830
or dif_with_unpaid < 0
1831
):
1832
now = datetime.now()
1833
difference = round(dif_with_unpaid, 8)
1834
if (
1835
difference >= MIN_TRANSACTION_VALUE_NOTIFY
1836
or difference < 0
1837
and notificationsEnabled
1838
):
1839
notification = Notify()
1840
notification.title = get_string("duino_coin_wallet")
1841
notification.message = (
1842
get_string("notification_new_transaction")
1843
+ "\n"
1844
+ now.strftime("%d.%m.%Y %H:%M:%S\n")
1845
+ str(round(difference, 6))
1846
+ " DUCO")
1847
notification.icon = resources + "duco_color.png"
1848
notification.send(block=False)
1849
with sqlconn(resources + "wallet.db") as con:
1850
cur = con.cursor()
1851
cur.execute(
1852
"""INSERT INTO Transactions(Date, amount)
1853
VALUES(?, ?)""", (
1854
now.strftime("%d.%m.%Y %H:%M:%S"),
1855
round(difference, 8)))
1856
con.commit()
1857
unpaid_balance = 0
1858
else:
1859
unpaid_balance += float(balance) - float(oldbalance)
1860
except Exception as e:
1861
print("Retrying in 3s. (" + str(e) + ")")
1862
Timer(3, get_balance).start()
1863
1864
1865
def get_wbalance():
1866
if TRONPY_ENABLED:
1867
try:
1868
pubkeyfile = open(str(resources + "DUCOPubKey.pub"), "r")
1869
pub_key = pubkeyfile.read()
1870
pubkeyfile.close()
1871
wBalance = float(wduco.functions.balanceOf(pub_key)) / (10 ** 6)
1872
return wBalance
1873
except Exception:
1874
return 0.0
1875
else:
1876
return 0.0
1877
1878
1879
def update_balance_labels():
1880
global profit_array, profitCheck
1881
try:
1882
balancetext.set(str(round(global_balance, 7)) + " ᕲ")
1883
wbalancetext.set(str(get_wbalance()) + " wᕲ")
1884
balanceusdtext.set(
1885
"$" + str(round(global_balance * duco_fiat_value, 4)))
1886
1887
with sqlconn(resources + "wallet.db") as con:
1888
cur = con.cursor()
1889
cur.execute("SELECT rowid,* FROM Transactions ORDER BY rowid DESC")
1890
Transactions = cur.fetchall()
1891
transactionstext_format = ""
1892
for i, row in enumerate(Transactions, start=1):
1893
transactionstext_format += str(row[1]) + \
1894
" " + str(row[2]) + " DUCO\n"
1895
if i == 6:
1896
transactionstext_format = transactionstext_format.rstrip("\n")
1897
break
1898
transactionstext.set(transactionstext_format)
1899
1900
if profit_array[2] != 0:
1901
sessionprofittext.set(
1902
get_string("session") + ": "
1903
+ str(profit_array[0]) + " ᕲ")
1904
minuteprofittext.set(
1905
"≈" + str(profit_array[1]) + " ᕲ/"
1906
+ get_string("minute"))
1907
hourlyprofittext.set(
1908
"≈" + str(profit_array[2]) + " ᕲ/"
1909
+ get_string("hour"))
1910
dailyprofittext.set(
1911
"≈"
1912
+ str(profit_array[3])
1913
+ " ᕲ/"
1914
+ get_string("day")
1915
+ " ($"
1916
+ str(round(profit_array[3] * duco_fiat_value, 4))
1917
+ ")")
1918
else:
1919
if profitCheck > 10:
1920
sessionprofittext.set(get_string("sessionprofit_unavailable1"))
1921
minuteprofittext.set(get_string("sessionprofit_unavailable2"))
1922
hourlyprofittext.set("")
1923
dailyprofittext.set("")
1924
profitCheck += 1
1925
except Exception:
1926
_exit(0)
1927
Timer(1, update_balance_labels).start()
1928
1929
1930
def profit_calculator(start_bal):
1931
try: # Thanks Bilaboz for the code!
1932
global curr_bal, profit_array
1933
1934
prev_bal = curr_bal
1935
curr_bal = global_balance
1936
session = curr_bal - start_bal
1937
tensec = curr_bal - prev_bal
1938
minute = tensec * 6
1939
hourly = minute * 60
1940
daily = hourly * 24
1941
1942
if tensec >= 0:
1943
profit_array = [
1944
round(session, 8),
1945
round(minute, 6),
1946
round(hourly, 4),
1947
round(daily, 2)]
1948
except Exception:
1949
_exit(0)
1950
Timer(10, profit_calculator, [start_bal]).start()
1951
1952
1953
def send_funds_protocol(handler):
1954
recipientStr = recipient.get()
1955
amountStr = amount.get()
1956
1957
MsgBox = messagebox.askquestion(
1958
get_string("warning"),
1959
get_string("send_funds_warning")
1960
+ " "
1961
+ str(amountStr)
1962
+ " DUCO "
1963
+ get_string("send_funds_to")
1964
+ " "
1965
+ str(recipientStr)
1966
+ "?",
1967
icon="warning",)
1968
if MsgBox == "yes":
1969
soc = websocket.create_connection(WS_URI)
1970
soc.recv().decode()
1971
1972
soc.send(bytes(
1973
"LOGI,"
1974
+ str(username)
1975
+ ","
1976
+ str(password),
1977
encoding="utf8"))
1978
response = soc.recv().decode()
1979
soc.send(
1980
bytes(
1981
"SEND,"
1982
+ "-"
1983
+ ","
1984
+ str(recipientStr)
1985
+ ","
1986
+ str(amountStr),
1987
encoding="utf8"))
1988
response = soc.recv().decode().rstrip("\n").split(",")
1989
soc.close()
1990
1991
if "OK" in str(response[0]):
1992
MsgBox = messagebox.showinfo(response[0],
1993
response[1]
1994
+ "\nTXID:"
1995
+ response[2])
1996
else:
1997
MsgBox = messagebox.showwarning(response[0], response[1])
1998
root.update()
1999
2000
2001
def init_rich_presence():
2002
global RPC
2003
try:
2004
RPC = Presence(806985845320056884)
2005
RPC.connect()
2006
except Exception: # Discord not launched
2007
pass
2008
2009
2010
def update_rich_presence():
2011
startTime = int(time())
2012
while True:
2013
try:
2014
balance = round(global_balance, 4)
2015
RPC.update(
2016
details=str(balance)
2017
+ " ᕲ ($"
2018
+ str(round(duco_fiat_value * balance, 2))
2019
+ ")",
2020
start=startTime,
2021
large_image="duco",
2022
large_text="Duino-Coin, "
2023
+ "a coin that can be mined with almost everything, "
2024
+ "including AVR boards",
2025
buttons=[
2026
{"label": "Learn more",
2027
"url": "https://duinocoin.com"},
2028
{"label": "Discord Server",
2029
"url": "https://discord.gg/k48Ht5y"}])
2030
except Exception: # Discord not launched
2031
pass
2032
sleep(15)
2033
2034
2035
class Wallet:
2036
def __init__(self, master):
2037
global recipient
2038
global amount
2039
global balancetext
2040
global wbalancetext
2041
global sessionprofittext
2042
global minuteprofittext
2043
global hourlyprofittext
2044
global dailyprofittext
2045
global balanceusdtext
2046
global transactionstext
2047
global curr_bal
2048
global profit_array
2049
try:
2050
loading.destroy()
2051
except Exception:
2052
pass
2053
2054
textFont4 = Font(
2055
size=14,
2056
weight="bold")
2057
TEXT_FONT_BOLD_LARGE = Font(
2058
size=12,
2059
weight="bold")
2060
TEXT_FONT_BOLD = Font(
2061
size=18,
2062
weight="bold")
2063
TEXT_FONT = Font(
2064
size=12,
2065
weight="normal")
2066
2067
self.master = master
2068
master.resizable(False, False)
2069
master.configure(background=BACKGROUND_COLOR)
2070
master.title(get_string("duino_coin_wallet"))
2071
2072
Label(
2073
master,
2074
text=get_string("uppercase_duino_coin_wallet")
2075
+ ": "
2076
+ str(username),
2077
font=TEXT_FONT_BOLD_LARGE,
2078
foreground=FOREGROUND_COLOR,
2079
background=BACKGROUND_COLOR,
2080
).grid(
2081
row=0,
2082
column=0,
2083
sticky=S + W,
2084
columnspan=4,
2085
pady=(5, 0),
2086
padx=(5, 0))
2087
2088
balancetext = StringVar()
2089
wbalancetext = StringVar()
2090
balancetext.set(get_string("please_wait"))
2091
if TRONPY_ENABLED:
2092
wbalancetext.set(get_string("please_wait"))
2093
else:
2094
wbalancetext.set("0.00")
2095
balanceLabel = Label(
2096
master,
2097
textvariable=balancetext,
2098
font=TEXT_FONT_BOLD,
2099
foreground=FOREGROUND_COLOR_SECONDARY,
2100
background=BACKGROUND_COLOR)
2101
balanceLabel.grid(row=1,
2102
column=0,
2103
columnspan=3,
2104
sticky=S + W,
2105
padx=(5, 0))
2106
2107
wbalanceLabel = Label(
2108
master,
2109
textvariable=wbalancetext,
2110
font=textFont4,
2111
foreground=FOREGROUND_COLOR_SECONDARY,
2112
background=BACKGROUND_COLOR)
2113
wbalanceLabel.grid(row=2,
2114
column=0,
2115
columnspan=3,
2116
sticky=S + W,
2117
padx=(5, 0))
2118
2119
balanceusdtext = StringVar()
2120
balanceusdtext.set(get_string("please_wait"))
2121
2122
Label(
2123
master,
2124
textvariable=balanceusdtext,
2125
font=TEXT_FONT,
2126
background=BACKGROUND_COLOR,
2127
foreground=FONT_COLOR,
2128
).grid(row=1,
2129
column=3,
2130
sticky=S + E,
2131
pady=(0, 1.5),
2132
padx=(0, 5))
2133
2134
separator = ttk.Separator(master, orient="horizontal")
2135
separator.grid(
2136
row=4,
2137
column=0,
2138
sticky=N + S + E + W,
2139
columnspan=4,
2140
padx=(5, 5),
2141
pady=(0, 5))
2142
2143
def clear_recipient_placeholder(self):
2144
recipient.delete("0", "100")
2145
2146
def clear_amount_placeholder(self):
2147
amount.delete("0", "100")
2148
2149
Label(
2150
master,
2151
text=get_string("recipient"),
2152
font=TEXT_FONT,
2153
background=BACKGROUND_COLOR,
2154
foreground=FONT_COLOR,
2155
).grid(row=5,
2156
column=0,
2157
sticky=W + S,
2158
padx=(5, 0))
2159
2160
recipient = Entry(
2161
master,
2162
border="0",
2163
font=TEXT_FONT,
2164
foreground=FOREGROUND_COLOR_SECONDARY,
2165
background=BACKGROUND_COLOR)
2166
recipient.grid(row=5,
2167
column=1,
2168
sticky=N + W + S + E,
2169
columnspan=3,
2170
padx=(0, 5))
2171
recipient.insert("0", "revox")
2172
recipient.bind("<FocusIn>", clear_recipient_placeholder)
2173
2174
Label(
2175
master,
2176
text=get_string("amount"),
2177
font=TEXT_FONT,
2178
background=BACKGROUND_COLOR,
2179
foreground=FONT_COLOR,
2180
).grid(row=6,
2181
column=0,
2182
sticky=W + S,
2183
padx=(5, 0))
2184
2185
amount = Entry(
2186
master,
2187
border="0",
2188
font=TEXT_FONT,
2189
foreground=FOREGROUND_COLOR_SECONDARY,
2190
background=BACKGROUND_COLOR)
2191
amount.grid(row=6,
2192
column=1,
2193
sticky=N + W + S + E,
2194
columnspan=3,
2195
padx=(0, 5))
2196
amount.insert("0", str(VERSION))
2197
amount.bind("<FocusIn>", clear_amount_placeholder)
2198
2199
sendLabel = Button(
2200
master,
2201
text=get_string("send_funds"),
2202
font=TEXT_FONT_BOLD_LARGE,
2203
foreground=FOREGROUND_COLOR,
2204
background=BACKGROUND_COLOR,
2205
activebackground=BACKGROUND_COLOR)
2206
sendLabel.grid(
2207
row=8,
2208
column=0,
2209
sticky=N + S + E + W,
2210
columnspan=4,
2211
padx=(5),
2212
pady=(1, 2))
2213
sendLabel.bind("<Button-1>", send_funds_protocol)
2214
2215
wrapLabel = Button(
2216
master,
2217
text=get_string("wrap_duco"),
2218
font=TEXT_FONT_BOLD_LARGE,
2219
foreground=FOREGROUND_COLOR,
2220
background=BACKGROUND_COLOR,
2221
activebackground=BACKGROUND_COLOR)
2222
wrapLabel.grid(
2223
row=9,
2224
column=0,
2225
sticky=N + S + E + W,
2226
columnspan=2,
2227
padx=(5, 1),
2228
pady=(1, 5))
2229
wrapLabel.bind("<Button-1>", wrapper_window)
2230
2231
wrapLabel = Button(
2232
master,
2233
text=get_string("unwrap_duco"),
2234
font=TEXT_FONT_BOLD_LARGE,
2235
foreground=FOREGROUND_COLOR,
2236
background=BACKGROUND_COLOR,
2237
activebackground=BACKGROUND_COLOR)
2238
wrapLabel.grid(
2239
row=9,
2240
column=2,
2241
sticky=N + S + E + W,
2242
columnspan=2,
2243
padx=(1, 5),
2244
pady=(1, 5))
2245
wrapLabel.bind("<Button-1>", unwrapper_window)
2246
2247
separator = ttk.Separator(master, orient="horizontal")
2248
separator.grid(
2249
row=10,
2250
column=0,
2251
sticky=N + S + E + W,
2252
columnspan=4,
2253
padx=(5, 5))
2254
2255
Label(
2256
master,
2257
text=get_string("estimated_profit"),
2258
font=TEXT_FONT_BOLD_LARGE,
2259
foreground=FOREGROUND_COLOR,
2260
background=BACKGROUND_COLOR,
2261
).grid(row=11,
2262
column=0,
2263
sticky=S + W,
2264
columnspan=4,
2265
pady=(5, 0),
2266
padx=(5, 0))
2267
2268
sessionprofittext = StringVar()
2269
sessionprofittext.set(get_string("please_wait_calculating"))
2270
sessionProfitLabel = Label(
2271
master,
2272
textvariable=sessionprofittext,
2273
font=TEXT_FONT,
2274
background=BACKGROUND_COLOR,
2275
foreground=FONT_COLOR)
2276
sessionProfitLabel.grid(
2277
row=12,
2278
column=0,
2279
sticky=W,
2280
columnspan=4,
2281
padx=5)
2282
2283
minuteprofittext = StringVar()
2284
minuteProfitLabel = Label(
2285
master,
2286
textvariable=minuteprofittext,
2287
font=TEXT_FONT,
2288
background=BACKGROUND_COLOR,
2289
foreground=FONT_COLOR)
2290
minuteProfitLabel.grid(
2291
row=13,
2292
column=0,
2293
sticky=W,
2294
columnspan=4,
2295
padx=5)
2296
2297
hourlyprofittext = StringVar()
2298
hourlyProfitLabel = Label(
2299
master,
2300
textvariable=hourlyprofittext,
2301
font=TEXT_FONT,
2302
background=BACKGROUND_COLOR,
2303
foreground=FONT_COLOR)
2304
hourlyProfitLabel.grid(
2305
row=14,
2306
column=0,
2307
sticky=W,
2308
columnspan=4,
2309
padx=5)
2310
2311
dailyprofittext = StringVar()
2312
dailyprofittext.set("")
2313
dailyProfitLabel = Label(
2314
master,
2315
textvariable=dailyprofittext,
2316
font=TEXT_FONT,
2317
background=BACKGROUND_COLOR,
2318
foreground=FONT_COLOR)
2319
dailyProfitLabel.grid(
2320
row=15,
2321
column=0,
2322
sticky=W,
2323
columnspan=4,
2324
padx=5)
2325
2326
separator = ttk.Separator(master, orient="horizontal")
2327
separator.grid(
2328
row=16,
2329
column=0,
2330
sticky=N + S + E + W,
2331
columnspan=4,
2332
padx=5)
2333
2334
Label(
2335
master,
2336
text=get_string("local_transactions"),
2337
font=TEXT_FONT_BOLD_LARGE,
2338
foreground=FOREGROUND_COLOR,
2339
background=BACKGROUND_COLOR,
2340
).grid(row=17,
2341
column=0,
2342
sticky=S + W,
2343
columnspan=4,
2344
pady=(5, 0),
2345
padx=(5, 0))
2346
2347
transactionstext = StringVar()
2348
transactionstext.set("")
2349
transactionstextLabel = Label(
2350
master,
2351
textvariable=transactionstext,
2352
font=TEXT_FONT,
2353
justify=LEFT,
2354
background=BACKGROUND_COLOR,
2355
foreground=FONT_COLOR)
2356
transactionstextLabel.grid(
2357
row=18,
2358
column=0,
2359
sticky=W,
2360
columnspan=4,
2361
padx=5,
2362
pady=(0, 5))
2363
2364
separator = ttk.Separator(master,
2365
orient="horizontal")
2366
separator.grid(
2367
row=19,
2368
column=0,
2369
sticky=N + S + E + W,
2370
columnspan=4,
2371
padx=5,
2372
pady=(0, 10))
2373
2374
original = Image.open(resources + "transactions.png")
2375
resized = original.resize((58, 58), Image.ANTIALIAS)
2376
transactions = ImageTk.PhotoImage(resized)
2377
transactions.image = transactions
2378
transactionsLabel = Label(
2379
master,
2380
image=transactions,
2381
background=BACKGROUND_COLOR,
2382
foreground=FONT_COLOR)
2383
transactionsLabel.grid(
2384
row=20,
2385
column=0,
2386
sticky=N + S + W + E,
2387
pady=(0, 5))
2388
transactionsLabel.bind("<Button>", transactions_window)
2389
2390
original = Image.open(resources + "calculator.png")
2391
resized = original.resize((58, 58), Image.ANTIALIAS)
2392
calculator = ImageTk.PhotoImage(resized)
2393
calculator.image = calculator
2394
calculatorLabel = Label(
2395
master,
2396
image=calculator,
2397
background=BACKGROUND_COLOR,
2398
foreground=FONT_COLOR)
2399
calculatorLabel.grid(
2400
row=20,
2401
column=1,
2402
sticky=N + S + W + E,
2403
padx=(0, 5),
2404
pady=(0, 5))
2405
calculatorLabel.bind("<Button>", currency_converter_window)
2406
2407
original = Image.open(resources + "stats.png")
2408
resized = original.resize((58, 58), Image.ANTIALIAS)
2409
stats = ImageTk.PhotoImage(resized)
2410
stats.image = stats
2411
statsLabel = Label(
2412
master,
2413
image=stats,
2414
background=BACKGROUND_COLOR,
2415
foreground=FONT_COLOR)
2416
statsLabel.grid(
2417
row=20,
2418
column=2,
2419
sticky=N + S + W + E,
2420
padx=(0, 5),
2421
pady=(0, 5))
2422
statsLabel.bind("<Button>", statistics_window)
2423
2424
original = Image.open(resources + "settings.png")
2425
resized = original.resize((58, 58), Image.ANTIALIAS)
2426
settings = ImageTk.PhotoImage(resized)
2427
settings.image = settings
2428
settingsLabel = Label(
2429
master,
2430
image=settings,
2431
background=BACKGROUND_COLOR,
2432
foreground=FONT_COLOR)
2433
settingsLabel.grid(
2434
row=20,
2435
column=3,
2436
sticky=N + S + W + E,
2437
padx=(0, 10),
2438
pady=(0, 5))
2439
settingsLabel.bind("<Button>", settings_window)
2440
2441
root.iconphoto(True, PhotoImage(file=resources + "duco_color.png"))
2442
start_balance = global_balance
2443
curr_bal = start_balance
2444
profit_calculator(start_balance)
2445
update_balance_labels()
2446
2447
root.mainloop()
2448
2449
2450
try:
2451
from pypresence import Presence
2452
except ModuleNotFoundError:
2453
print("Pypresence is not installed."
2454
+ "Wallet will try to install it. "
2455
+ "If it fails, please manually install \"pypresence\".")
2456
install("pypresence")
2457
2458
try:
2459
from PIL import Image, ImageTk
2460
except ModuleNotFoundError:
2461
print("Pillow is not installed. "
2462
+ "Wallet will try to install it. "
2463
+ "If it fails, please manually install \"Pillow\".")
2464
install("Pillow")
2465
2466
try:
2467
from notifypy import Notify
2468
except ModuleNotFoundError:
2469
print("Notify-py is not installed. "
2470
+ "Continuing without notification system.")
2471
notificationsEnabled = False
2472
else:
2473
notificationsEnabled = True
2474
2475
try:
2476
from cryptography.fernet import Fernet, InvalidToken
2477
from cryptography.hazmat.backends import default_backend
2478
from cryptography.hazmat.primitives import hashes
2479
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
2480
2481
backend = default_backend()
2482
except ModuleNotFoundError:
2483
print("Cryptography is not installed. "
2484
+ "Please manually install \"cryptography\"."
2485
+ "\nExiting in 15s.")
2486
sleep(15)
2487
_exit(1)
2488
2489
try:
2490
import secrets
2491
except ModuleNotFoundError:
2492
print("Secrets is not installed. "
2493
+ "Please manually install \"secrets\"."
2494
+ "\nExiting in 15s.")
2495
sleep(15)
2496
_exit(1)
2497
2498
try:
2499
from base64 import urlsafe_b64decode as b64d
2500
from base64 import urlsafe_b64encode as b64e
2501
except ModuleNotFoundError:
2502
print("Base64 is not installed. "
2503
+ "Please manually install \"base64\""
2504
+ "\nExiting in 15s.")
2505
sleep(15)
2506
_exit(1)
2507
2508
try:
2509
import websocket
2510
except ModuleNotFoundError:
2511
print("websocket-client is not installed. "
2512
+ "Wallet will try to install it. "
2513
+ "If it fails, please manually install \"websocket-client\".")
2514
install("websocket-client")
2515
2516
try:
2517
import tronpy
2518
from tronpy.keys import PrivateKey
2519
TRONPY_ENABLED = True
2520
except ModuleNotFoundError:
2521
TRONPY_ENABLED = False
2522
print("Tronpy is not installed. "
2523
+ "Please manually install \"tronpy\" "
2524
+ "if you intend on using wDUCO wrapper.")
2525
else:
2526
try:
2527
tron = tronpy.Tron()
2528
wduco = tron.get_contract("TWYaXdxA12JywrUdou3PFD1fvx2PWjqK9U")
2529
except:
2530
TRONPY_ENABLED = False
2531
print("Tron-side error, disabling wrapper for this session")
2532
2533
if not path.exists(resources):
2534
mkdir(resources)
2535
2536
with sqlconn(resources + "/wallet.db") as con:
2537
cur = con.cursor()
2538
cur.execute(
2539
"""CREATE TABLE IF NOT EXISTS
2540
Transactions(Date TEXT, amount REAL)""")
2541
cur.execute(
2542
"""CREATE TABLE IF NOT EXISTS
2543
UserData(username TEXT, password TEXT, useWrapper TEXT)""")
2544
con.commit()
2545
2546
if not Path(resources + "duco.png").is_file():
2547
urlretrieve("https://i.imgur.com/9JzxR0B.png", resources + "duco.png")
2548
2549
if not Path(resources + "duco_color.png").is_file():
2550
urlretrieve(
2551
"https://github.com/"
2552
+ "revoxhere/"
2553
+ "duino-coin/blob/master/"
2554
+ "Resources/duco.png?raw=true",
2555
resources + "duco_color.png")
2556
2557
if not Path(resources + "calculator.png").is_file():
2558
urlretrieve("https://i.imgur.com/iqE28Ej.png",
2559
resources + "calculator.png")
2560
2561
if not Path(resources + "exchange.png").is_file():
2562
urlretrieve("https://i.imgur.com/0qMtoZ7.png",
2563
resources + "exchange.png")
2564
2565
if not Path(resources + "discord.png").is_file():
2566
urlretrieve("https://i.imgur.com/LoctALa.png",
2567
resources + "discord.png")
2568
2569
if not Path(resources + "github.png").is_file():
2570
urlretrieve("https://i.imgur.com/PHEfWbl.png",
2571
resources + "github.png")
2572
2573
if not Path(resources + "settings.png").is_file():
2574
urlretrieve("https://i.imgur.com/NNEI4WL.png",
2575
resources + "settings.png")
2576
2577
if not Path(resources + "transactions.png").is_file():
2578
urlretrieve("https://i.imgur.com/nbVPlKk.png",
2579
resources + "transactions.png")
2580
2581
if not Path(resources + "stats.png").is_file():
2582
urlretrieve("https://i.imgur.com/KRfHZUM.png",
2583
resources + "stats.png")
2584
2585
if not Path(resources + "langs.json").is_file():
2586
urlretrieve(
2587
"https://raw.githubusercontent.com/"
2588
+ "revoxhere/"
2589
+ "duino-coin/master/Resources/"
2590
+ "Wallet_langs.json",
2591
resources + "langs.json")
2592
2593
# Load language strings depending on system locale
2594
with open(resources + "langs.json", "r", encoding="utf-8") as lang_file:
2595
lang_file = jsonloads(lang_file.read())
2596
try:
2597
locale = getdefaultlocale()[0]
2598
if locale.startswith("es"):
2599
lang = "spanish"
2600
elif locale.startswith("pl"):
2601
lang = "polish"
2602
elif locale.startswith("fr"):
2603
lang = "french"
2604
elif locale.startswith("bg"):
2605
lang = "bulgarian"
2606
elif locale.startswith("nl"):
2607
lang = "dutch"
2608
elif locale.startswith("ru"):
2609
lang = "russian"
2610
elif locale.startswith("uk"):
2611
lang = "ukrainian"
2612
elif locale.startswith("de"):
2613
lang = "german"
2614
elif locale.startswith("tr"):
2615
lang = "turkish"
2616
elif locale.startswith("it"):
2617
lang = "italian"
2618
elif locale.startswith("zh"):
2619
lang = "chinese_simplified"
2620
elif locale.startswith("sk"):
2621
lang = "slovak"
2622
elif locale.startswith("th"):
2623
lang = "thai"
2624
elif locale.startswith("ko"):
2625
lang = "korean"
2626
elif locale.startswith("fi"):
2627
lang = "finnish"
2628
else:
2629
lang = "english"
2630
except IndexError:
2631
lang = "english"
2632
2633
if __name__ == "__main__":
2634
with sqlconn(resources + "wallet.db") as con:
2635
cur = con.cursor()
2636
cur.execute("SELECT COUNT(username) FROM UserData")
2637
userdata_count = cur.fetchall()[0][0]
2638
if userdata_count < 1:
2639
root = Tk()
2640
lf = LoginFrame(root)
2641
root.mainloop()
2642
cur = con.cursor()
2643
cur.execute("SELECT COUNT(username) FROM UserData")
2644
userdata_count = cur.fetchall()[0][0]
2645
2646
if userdata_count >= 1:
2647
loading_window()
2648
cur = con.cursor()
2649
cur.execute("SELECT * FROM UserData")
2650
userdata_query = cur.fetchone()
2651
username = userdata_query[0]
2652
passwordEnc = (userdata_query[1]).decode("utf-8")
2653
password = b64decode(passwordEnc).decode("utf8")
2654
status.config(text=get_string("preparing_wallet_window"))
2655
loading.update()
2656
try:
2657
# Start duco price updater
2658
get_duco_price()
2659
get_balance()
2660
init_rich_presence()
2661
Thread(target=update_rich_presence).start()
2662
try:
2663
# Destroy loading dialog and start the main wallet window
2664
loading.destroy()
2665
except Exception:
2666
pass
2667
root = Tk()
2668
my_gui = Wallet(root)
2669
except Exception as e:
2670
print(e)
2671
_exit(0)
2672
2673