Skip to content

Commit 0373eb7

Browse files
authored
Merge pull request #6 from RustambekSh/patch-2
Update steller_wallet.py
2 parents 60e9cdd + 504173b commit 0373eb7

File tree

1 file changed

+115
-157
lines changed

1 file changed

+115
-157
lines changed

steller_wallet.py

+115-157
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import customtkinter as ctk
22
from tkinter import Toplevel
33
from stellar_sdk import Keypair, Server, TransactionBuilder, Network, Asset
4-
from stellar_sdk.exceptions import NotFoundError # for better error descriptions
4+
from stellar_sdk.exceptions import NotFoundError # for better error descriptions
5+
56

67
class StellarWalletApp:
78
def __init__(self, root):
@@ -10,83 +11,90 @@ def __init__(self, root):
1011
self.root.geometry("500x700")
1112
self.root.resizable(False, False)
1213

13-
# Configure grid layout for basic centering
1414
self.root.grid_columnconfigure(0, weight=1)
15-
self.root.grid_rowconfigure(0, weight=1)
16-
self.root.grid_rowconfigure(10, weight=1)
15+
16+
# Style configurations
17+
self.style_config = {
18+
"label": {"font": ("Arial", 15, "bold")},
19+
"entry": {"font": ("Courier New", 14), "border_width": 2, "border_color": '#2da572', "height": 40,
20+
"width": 350},
21+
"button": {"text_color": "black", "font": ("Courier New", 14, "bold"), "width": 250, "height": 40},
22+
}
23+
24+
# Grid layout configuration
25+
self.grid_config = {
26+
"padx": 10,
27+
"pady": (10, 5),
28+
29+
}
1730

1831
# Create Widgets
1932
self.create_widgets()
2033

2134
def create_widgets(self):
2235
# Title Label
23-
self.title_label = ctk.CTkLabel(self.root, text="Stellar Wallet 💳", font=("Arial", 20, "bold"))
24-
self.title_label.grid(row=1, column=0, padx=10, pady=(10, 5), sticky="n")
25-
26-
# Public Key Label
27-
self.public_key_label = ctk.CTkLabel(self.root, text="Public Key:", font=("Arial", 15, "bold"))
28-
self.public_key_label.grid(row=2, column=0, padx=10, pady=(10, 5), sticky="w")
29-
30-
# Public Key Entry
31-
self.public_key_entry = ctk.CTkEntry(self.root,
32-
placeholder_text="Enter Public Key",
33-
font=("Courier New", 14),
34-
border_width=2,
35-
border_color='#2da572',
36-
height=40,
37-
width=350)
38-
self.public_key_entry.grid(row=3, column=0, padx=(10, 0), pady=(5, 15))
39-
40-
# Secret Key Label
41-
self.secret_key_label = ctk.CTkLabel(self.root, text="Secret Key:", font=("Arial", 15, "bold"))
42-
self.secret_key_label.grid(row=4, column=0, padx=10, pady=(10, 5), sticky="w")
43-
44-
# Secret Key Entry
45-
self.secret_key_entry = ctk.CTkEntry(self.root,
46-
placeholder_text="Enter Secret Key",
47-
font=("Courier New", 14),
48-
border_width=2,
49-
border_color='#2da572',
50-
height=40,
51-
show="*",
52-
width=350)
53-
self.secret_key_entry.grid(row=5, column=0, padx=(10, 0), pady=(5, 15))
54-
55-
# Create Account Button
56-
self.create_account_button = ctk.CTkButton(self.root,
57-
text="Create Account",
58-
text_color="black",
59-
font=("Courier New", 14,"bold"),
60-
width=250,
61-
height=40,
62-
command=self.create_account)
63-
self.create_account_button.grid(row=6, column=0, padx=(10, 0), pady=(10, 10))
64-
65-
# Check Balance Button
66-
self.balance_button = ctk.CTkButton(self.root,
67-
text="Check Balance",
68-
text_color="black",
69-
font=("Courier New", 14),
70-
width=250,
71-
height=40,
72-
command=self.check_balance)
73-
self.balance_button.grid(row=7, column=0, padx=(10, 0), pady=(10, 10))
74-
75-
# Send Payment Button
76-
self.send_payment_button = ctk.CTkButton(self.root,
77-
text="Send Payment",
78-
text_color="black",
79-
font=("Courier New", 14),
80-
width=250,
81-
height=40,
82-
command=self.send_payment)
83-
self.send_payment_button.grid(row=8, column=0, padx=(10, 0), pady=(10, 10))
36+
title_label = ctk.CTkLabel(self.root, text="Stellar Wallet 💳", font=("Arial", 20, "bold"))
37+
title_label.grid(row=0, column=0, pady=(20, 30), sticky="n")
38+
39+
# Public Key Section
40+
self.public_key_entry = self._create_labeled_entry("Public Key:", row=1)
41+
42+
# Secret Key Section
43+
self.secret_key_entry = self._create_labeled_entry("Secret Key:", row=3, show="*")
44+
45+
# Buttons
46+
buttons_info = [
47+
("Create Account", self.create_account),
48+
("Check Balance", self.check_balance),
49+
("Send Payment", self.send_payment),
50+
]
51+
for idx, (btn_text, btn_command) in enumerate(buttons_info):
52+
button = ctk.CTkButton(self.root, text=btn_text, command=btn_command, **self.style_config["button"])
53+
button.grid(row=5 + idx, column=0, pady=(15, 10))
8454

8555
# Result Label
8656
self.result_label = ctk.CTkLabel(self.root, text="", font=("Arial", 14))
87-
self.result_label.grid(row=9, column=0, padx=(10, 0), pady=(20, 20))
57+
self.result_label.grid(row=8, column=0, pady=(20, 20))
58+
59+
def _create_labeled_entry(self, label_text, row, show=None):
60+
"""Helper method to create labeled entry widgets."""
61+
label = ctk.CTkLabel(self.root, text=label_text, **self.style_config["label"])
62+
label.grid(row=row, column=0, **self.grid_config)
63+
64+
entry = ctk.CTkEntry(self.root, **self.style_config["entry"], show=show)
65+
entry.grid(row=row + 1, column=0, padx=(10, 0), pady=(5, 15))
66+
67+
return entry
68+
69+
def _get_input(self, prompt_text, input_type=str):
70+
"""Unified method to get user input with type conversion."""
71+
input_window = Toplevel(self.root)
72+
input_window.title(prompt_text)
73+
input_window.geometry("400x200")
74+
input_window.resizable(False, False)
75+
76+
prompt_label = ctk.CTkLabel(input_window, text=prompt_text, font=("Arial", 15, "bold"))
77+
prompt_label.pack(pady=(20, 10))
78+
79+
input_entry = ctk.CTkEntry(input_window, font=("Arial", 15, "bold"), width=300)
80+
input_entry.pack(pady=10)
81+
82+
input_value = []
83+
84+
def submit_input():
85+
try:
86+
value = input_type(input_entry.get())
87+
input_value.append(value)
88+
except ValueError:
89+
input_value.append(None)
90+
input_window.destroy()
8891

92+
submit_button = ctk.CTkButton(input_window, text="Submit", command=submit_input, font=("Arial", 15, "bold"),
93+
width=150)
94+
submit_button.pack(pady=10)
8995

96+
input_window.wait_window()
97+
return input_value[0] if input_value else None
9098

9199
def create_account(self):
92100
"""Generate a new Stellar account and display the keys."""
@@ -99,75 +107,83 @@ def create_account(self):
99107

100108
def check_balance(self):
101109
"""Check and display the balance of the account."""
110+
public_key = self.public_key_entry.get()
111+
if not public_key:
112+
self.show_toplevel_message("Public key is required.")
113+
return
114+
102115
try:
103-
public_key = self.public_key_entry.get()
104116
server = Server("https://horizon-testnet.stellar.org")
105117
account = server.accounts().account_id(public_key).call()
106118
balances = account['balances']
107119
if not balances or all(float(b['balance']) == 0 for b in balances):
108-
self.show_toplevel_message("No balance")
120+
self.show_toplevel_message("No balance found.")
109121
else:
110122
balance_text = "\n".join([f"Asset Type: {b['asset_type']}, Balance: {b['balance']}" for b in balances])
111123
self.result_label.configure(text=balance_text)
112-
except Exception:
113-
self.show_toplevel_message("Failed to retrieve balance")
124+
except NotFoundError:
125+
self.show_toplevel_message("Account not found.")
126+
except Exception as e:
127+
self.show_toplevel_message(f"Failed to retrieve balance: {str(e)}")
114128

115129
def send_payment(self):
116130
"""Send a payment to another Stellar account."""
117-
try:
118-
source_secret = self.secret_key_entry.get()
119-
if not source_secret:
120-
self.show_toplevel_message("Payment unsuccessful: Secret key is required")
121-
return
131+
source_secret = self.secret_key_entry.get()
132+
if not source_secret:
133+
self.show_toplevel_message("Payment unsuccessful: Secret key is required.")
134+
return
122135

123-
destination_public = self.prompt_input("Enter destination public key:")
124-
print(f"Destination Public Key: {destination_public}") # Debugging line
125-
amount = self.prompt_float_input("Enter amount to send:")
126-
print(f"Amount to send: {amount}") # Debugging line
136+
destination_public = self._get_input("Enter destination public key:")
137+
amount = self._get_input("Enter amount to send:", float)
127138

128-
if not destination_public or not amount:
129-
self.show_toplevel_message("Payment unsuccessful: All fields are required")
130-
return
139+
if not destination_public or not amount:
140+
self.show_toplevel_message("Payment unsuccessful: All fields are required.")
141+
return
131142

143+
try:
132144
source_keypair = Keypair.from_secret(source_secret)
133145
server = Server("https://horizon-testnet.stellar.org")
134146

135147
# Check if source account exists
136148
try:
137149
source_account = server.load_account(source_keypair.public_key)
138150
except NotFoundError:
139-
self.show_toplevel_message("Payment unsuccessful: Source account not found")
151+
self.show_toplevel_message("Payment unsuccessful: Source account not found.")
140152
return
141153

142154
# Check if destination account exists
143155
try:
144156
server.accounts().account_id(destination_public).call()
145157
except NotFoundError:
146-
self.show_toplevel_message("Payment unsuccessful: Destination account not found")
158+
self.show_toplevel_message("Payment unsuccessful: Destination account not found.")
147159
return
148160

149-
transaction = TransactionBuilder(
150-
source_account,
151-
network_passphrase=Network.TESTNET_NETWORK_PASSPHRASE,
152-
base_fee=100
153-
).add_text_memo("Stellar Payment").append_payment_op(
154-
destination=destination_public,
155-
amount=str(amount),
156-
asset=Asset.native() # Specify that the asset is the native XLM
157-
).build()
158-
161+
transaction = (
162+
TransactionBuilder(
163+
source_account,
164+
network_passphrase=Network.TESTNET_NETWORK_PASSPHRASE,
165+
base_fee=100
166+
)
167+
.add_text_memo("Stellar Payment")
168+
.append_payment_op(
169+
destination=destination_public,
170+
amount=str(amount),
171+
asset=Asset.native() # Specify that the asset is the native XLM
172+
)
173+
.build()
174+
)
159175
transaction.sign(source_keypair)
160176
response = server.submit_transaction(transaction)
161-
self.result_label.configure(text=f"Payment sent!\nTransaction Hash:\n{response['hash']}", font=("Courier New", 10))
162-
177+
self.result_label.configure(text=f"Payment sent!\nTransaction Hash:\n{response['hash']}",
178+
font=("Courier New", 10))
163179
except Exception as e:
164-
print(f"Exception occurred: {e}") # Debugging line
165-
self.show_toplevel_message("Payment unsuccessful")
180+
self.show_toplevel_message(f"Payment unsuccessful: {str(e)}")
181+
166182
def show_toplevel_message(self, message):
167183
"""Display a top-level window with a message."""
168184
top = Toplevel(self.root)
169185
top.title("Notification")
170-
top.geometry("400x400")
186+
top.geometry("400x200")
171187
top.resizable(False, False)
172188

173189
msg = ctk.CTkLabel(top, text=message, font=("Arial", 15, "bold"))
@@ -176,68 +192,10 @@ def show_toplevel_message(self, message):
176192
button = ctk.CTkButton(top, text="OK", command=top.destroy, font=("Arial", 15, "bold"), width=150)
177193
button.pack(pady=20)
178194

179-
def prompt_input(self, prompt_text):
180-
"""Prompt for string input using a custom Toplevel window."""
181-
input_window = Toplevel(self.root)
182-
input_window.title(prompt_text)
183-
input_window.geometry("400x400")
184-
input_window.resizable(False, False)
185-
186-
prompt_label = ctk.CTkLabel(input_window, text=prompt_text, font=("Arial", 15, "bold"))
187-
prompt_label.pack(pady=(40, 20))
188-
189-
input_entry = ctk.CTkEntry(input_window, font=("Arial", 15, "bold"), width=300)
190-
input_entry.pack(pady=20)
191-
192-
input_value = []
193-
194-
def submit_input():
195-
input_value.append(input_entry.get())
196-
input_window.destroy()
197-
198-
submit_button = ctk.CTkButton(input_window, text="Submit", command=submit_input, font=("Arial", 15, "bold"),
199-
width=150)
200-
submit_button.pack(pady=20)
201-
202-
input_window.wait_window()
203-
204-
return input_value[0] if input_value else None
205-
206-
def prompt_float_input(self, prompt_text):
207-
"""Prompt for float input using a custom Toplevel window."""
208-
input_window = Toplevel(self.root)
209-
input_window.title(prompt_text)
210-
input_window.geometry("400x400")
211-
input_window.resizable(False, False)
212-
213-
prompt_label = ctk.CTkLabel(input_window, text=prompt_text, font=("Arial", 15, "bold"))
214-
prompt_label.pack(pady=(40, 20))
215-
216-
input_entry = ctk.CTkEntry(input_window, font=("Arial", 15, "bold"), width=300)
217-
input_entry.pack(pady=20)
218-
219-
input_value = []
220-
221-
def submit_input():
222-
try:
223-
input_value.append(float(input_entry.get()))
224-
except ValueError:
225-
input_value.append(None)
226-
input_window.destroy()
227-
228-
submit_button = ctk.CTkButton(input_window, text="Submit", command=submit_input, font=("Arial", 15, "bold"),
229-
width=150)
230-
submit_button.pack(pady=20)
231-
232-
input_window.wait_window()
233-
234-
return input_value[0] if input_value else None
235-
236195

237196
if __name__ == "__main__":
238197
ctk.set_appearance_mode("dark") # Use system theme
239198
ctk.set_default_color_theme("green") # Default color theme without customization
240-
241199
root = ctk.CTk()
242200
app = StellarWalletApp(root)
243201
root.mainloop()

0 commit comments

Comments
 (0)