Rooobert commited on
Commit
6aa5728
·
verified ·
1 Parent(s): 93b307b

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +295 -0
app.py ADDED
@@ -0,0 +1,295 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ import secrets
4
+ import hashlib
5
+ import tempfile
6
+ import subprocess
7
+ import json
8
+ from starknet_py.net.account.account import Account
9
+ from starknet_py.net.models import StarknetChainId
10
+ from starknet_py.net.signer.stark_curve_signer import KeyPair
11
+ from starknet_py.net.gateway_client import GatewayClient
12
+ from starknet_py.contract import Contract
13
+
14
+ # Set page config
15
+ st.set_page_config(
16
+ page_title="StarkNet 開發工作流程",
17
+ page_icon="🌟",
18
+ layout="wide"
19
+ )
20
+
21
+ # Application title
22
+ st.title("StarkNet 開發完整工作流程")
23
+ st.markdown("""
24
+ 這個應用演示了進行 StarkNet 開發的完整流程,包括:
25
+ 1. 編寫和編譯 Cairo 合約
26
+ 2. 生成 StarkNet 密鑰對和地址
27
+ 3. 與 StarkNet 進行交互
28
+ """)
29
+
30
+ # Sidebar
31
+ st.sidebar.header("StarkNet 開發工具")
32
+ selected_section = st.sidebar.radio(
33
+ "選擇步驟",
34
+ ["編寫和編譯合約", "生成密鑰對和地址", "與 StarkNet 交互"]
35
+ )
36
+
37
+ # Function to compile Cairo contract
38
+ def compile_cairo_contract(cairo_code):
39
+ with tempfile.NamedTemporaryFile(suffix='.cairo', delete=False) as tmp_file:
40
+ tmp_file.write(cairo_code.encode())
41
+ tmp_file_path = tmp_file.name
42
+
43
+ output_file = f"{tmp_file_path}_compiled.json"
44
+
45
+ try:
46
+ result = subprocess.run(
47
+ ["cairo-compile", tmp_file_path, "--output", output_file],
48
+ capture_output=True,
49
+ text=True,
50
+ check=True
51
+ )
52
+
53
+ # Read compiled contract
54
+ with open(output_file, 'r') as f:
55
+ compiled_contract = json.load(f)
56
+
57
+ # Clean up temporary files
58
+ os.remove(tmp_file_path)
59
+ os.remove(output_file)
60
+
61
+ return compiled_contract, result.stdout
62
+ except subprocess.CalledProcessError as e:
63
+ return None, e.stderr
64
+ except Exception as e:
65
+ return None, str(e)
66
+
67
+ # Function to generate StarkNet keys
68
+ def generate_starknet_keys():
69
+ # Generate random private key (251 bits for StarkNet)
70
+ private_key = secrets.randbits(251)
71
+ private_key_hex = hex(private_key)
72
+
73
+ # Create key pair
74
+ key_pair = KeyPair.from_private_key(private_key)
75
+
76
+ # Get public key
77
+ public_key = key_pair.public_key
78
+ public_key_hex = hex(public_key)
79
+
80
+ # Try to get an appropriate chain ID
81
+ try:
82
+ chain_id = StarknetChainId.GOERLI
83
+ except AttributeError:
84
+ try:
85
+ chain_id = StarknetChainId.SEPOLIA
86
+ except AttributeError:
87
+ # Use a generic testnet ID if above networks are not available
88
+ chain_id = 1536727068981429685321
89
+
90
+ # Create account object
91
+ account = Account(
92
+ address=0, # Will be populated after deployment
93
+ client=None, # Not needed for this example
94
+ key_pair=key_pair,
95
+ chain=chain_id
96
+ )
97
+
98
+ # Get account address
99
+ address = account.address
100
+
101
+ return {
102
+ "private_key": private_key_hex,
103
+ "public_key": public_key_hex,
104
+ "address": hex(address),
105
+ "chain_id": chain_id,
106
+ "key_pair": key_pair
107
+ }
108
+
109
+ # Section 1: Write and Compile Cairo Contract
110
+ if selected_section == "編寫和編譯合約":
111
+ st.header("1. 編寫和編譯 Cairo 合約")
112
+
113
+ # Default Cairo contract template
114
+ default_cairo_code = """%lang cairo
115
+
116
+ @external
117
+ func transfer{syscall_ptr: felt*, range_check_ptr}(
118
+ from_address: felt,
119
+ to_address: felt,
120
+ amount: felt
121
+ ) -> (success: felt):
122
+ # 這只是一個簡單的模擬轉帳函數
123
+ # 在實際應用中,您需要進行餘額檢查和狀態更新
124
+ return (1) # 返回成功
125
+ end
126
+
127
+ @view
128
+ func get_balance{syscall_ptr: felt*, range_check_ptr}(
129
+ address: felt
130
+ ) -> (balance: felt):
131
+ # 這只是一個簡單的模擬餘額查詢函數
132
+ # 在實際應用中,您需要從存儲中讀取真實的餘額
133
+ return (1000) # 返回模擬餘額
134
+ end
135
+ """
136
+
137
+ cairo_code = st.text_area("Cairo 合約代碼", default_cairo_code, height=400)
138
+
139
+ if st.button("編譯合約"):
140
+ with st.spinner("正在編譯 Cairo 合約..."):
141
+ compiled_contract, output = compile_cairo_contract(cairo_code)
142
+
143
+ if compiled_contract:
144
+ st.success("合約編譯成功!")
145
+ st.code(json.dumps(compiled_contract, indent=2), language="json")
146
+
147
+ # Save the compiled contract to session state for later use
148
+ st.session_state['compiled_contract'] = compiled_contract
149
+ else:
150
+ st.error("合約編譯失敗!")
151
+ st.code(output)
152
+
153
+ # Section 2: Generate StarkNet Keys
154
+ elif selected_section == "生成密鑰對和地址":
155
+ st.header("2. 生成 StarkNet 密鑰對和地址")
156
+
157
+ if st.button("生成新的密鑰對"):
158
+ with st.spinner("正在生成 StarkNet 密鑰..."):
159
+ keys_info = generate_starknet_keys()
160
+
161
+ # Save keys to session state
162
+ st.session_state['keys_info'] = keys_info
163
+
164
+ # Display keys information
165
+ st.subheader("StarkNet 密鑰信息")
166
+ st.markdown(f"""
167
+ - **私鑰**: `{keys_info['private_key']}`
168
+ - **公鑰**: `{keys_info['public_key']}`
169
+ - **地址**: `{keys_info['address']}`
170
+ - **網絡**: `{keys_info['chain_id']}`
171
+ """)
172
+
173
+ # Option to download keys as text file
174
+ keys_text = f"""私鑰: {keys_info['private_key']}
175
+ 公鑰: {keys_info['public_key']}
176
+ 地址: {keys_info['address']}
177
+ 網絡: {keys_info['chain_id']}"""
178
+
179
+ st.download_button(
180
+ label="下載密鑰信息",
181
+ data=keys_text,
182
+ file_name="starknet_keys.txt",
183
+ mime="text/plain"
184
+ )
185
+
186
+ # Display saved keys if available
187
+ if 'keys_info' in st.session_state:
188
+ st.subheader("已保存的 StarkNet 密鑰信息")
189
+ st.markdown(f"""
190
+ - **私鑰**: `{st.session_state['keys_info']['private_key']}`
191
+ - **公鑰**: `{st.session_state['keys_info']['public_key']}`
192
+ - **地址**: `{st.session_state['keys_info']['address']}`
193
+ - **網絡**: `{st.session_state['keys_info']['chain_id']}`
194
+ """)
195
+
196
+ # Section 3: Interact with StarkNet
197
+ elif selected_section == "與 StarkNet 交互":
198
+ st.header("3. 與 StarkNet 交互")
199
+
200
+ # Network selection
201
+ network = st.selectbox(
202
+ "選擇 StarkNet 網絡",
203
+ ["goerli", "sepolia", "mainnet"]
204
+ )
205
+
206
+ # Contract address input
207
+ contract_address = st.text_input("合約地址 (十六進制)", "0x")
208
+
209
+ # Check if we have compiled contract and keys
210
+ has_contract = 'compiled_contract' in st.session_state
211
+ has_keys = 'keys_info' in st.session_state
212
+
213
+ if not has_contract:
214
+ st.warning("請先在「編寫和編譯合約」步驟中編譯合約")
215
+
216
+ if not has_keys:
217
+ st.warning("請先在「生成密鑰對和地址」步驟中生成密鑰")
218
+
219
+ # Contract interaction section
220
+ if has_contract and has_keys and st.text_input("合約地址") != "0x":
221
+ st.subheader("合約交互")
222
+
223
+ # Function selection
224
+ function_option = st.radio(
225
+ "選擇函數",
226
+ ["transfer", "get_balance"]
227
+ )
228
+
229
+ if function_option == "transfer":
230
+ # Transfer function parameters
231
+ st.subheader("轉帳參數")
232
+ from_address = st.text_input("來源地址", value=st.session_state['keys_info']['address'])
233
+ to_address = st.text_input("目標地址", "0x")
234
+ amount = st.number_input("金額", min_value=1, value=100)
235
+
236
+ if st.button("執行轉帳"):
237
+ st.info("此功能在演示模式下,實際調用需要連接到 StarkNet 網絡")
238
+
239
+ # Here we would implement actual StarkNet interaction
240
+ st.code(f"""
241
+ # 實際執行代碼將如下:
242
+ client = GatewayClient(net="{network}")
243
+
244
+ contract = Contract(
245
+ address=int("{contract_address}", 16),
246
+ abi=st.session_state['compiled_contract']['abi'],
247
+ client=client
248
+ )
249
+
250
+ response = await account.execute(
251
+ calls=[
252
+ contract.functions["transfer"].prepare(
253
+ from_address=int("{from_address}", 16),
254
+ to_address=int("{to_address}", 16),
255
+ amount={amount}
256
+ )
257
+ ]
258
+ )
259
+ """, language="python")
260
+
261
+ elif function_option == "get_balance":
262
+ # Get balance function parameters
263
+ st.subheader("餘額查詢參數")
264
+ address = st.text_input("查詢地址", value=st.session_state['keys_info']['address'])
265
+
266
+ if st.button("查詢餘額"):
267
+ st.info("此功能在演示模式下,實際調用需要連接到 StarkNet 網絡")
268
+
269
+ # Here we would implement actual StarkNet interaction
270
+ st.code(f"""
271
+ # 實際執行代碼將如下:
272
+ client = GatewayClient(net="{network}")
273
+
274
+ contract = Contract(
275
+ address=int("{contract_address}", 16),
276
+ abi=st.session_state['compiled_contract']['abi'],
277
+ client=client
278
+ )
279
+
280
+ balance = await contract.functions["get_balance"].call(
281
+ address=int("{address}", 16)
282
+ )
283
+ """, language="python")
284
+
285
+ # Show a mock result
286
+ st.success("模擬結果: 餘額 = 1000")
287
+
288
+ # Footer
289
+ st.markdown("---")
290
+ st.markdown("### StarkNet 開發資源")
291
+ st.markdown("""
292
+ - [StarkNet 官方文檔](https://docs.starknet.io)
293
+ - [Cairo 語言文檔](https://cairo-lang.org)
294
+ - [StarkNet-py 庫文檔](https://github.com/software-mansion/starknet.py)
295
+ """)