Rooobert commited on
Commit
31e3c19
·
verified ·
1 Parent(s): 50f366a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +218 -231
app.py CHANGED
@@ -1,117 +1,54 @@
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}(
@@ -119,177 +56,227 @@ func transfer{syscall_ptr: felt*, range_check_ptr}(
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
- """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
 
2
  import secrets
3
  import hashlib
4
+ import os
5
  import subprocess
6
  import json
7
  from starknet_py.net.account.account import Account
8
  from starknet_py.net.models import StarknetChainId
9
  from starknet_py.net.signer.stark_curve_signer import KeyPair
 
 
10
 
 
11
  st.set_page_config(
12
+ page_title="StarkNet Development Toolkit",
13
  page_icon="🌟",
14
  layout="wide"
15
  )
16
 
17
+ st.title("StarkNet Development Toolkit")
18
+ st.markdown("A complete workflow for StarkNet development including contract compilation, key generation, and more.")
 
 
 
 
 
 
19
 
20
+ # Sidebar for navigation
21
+ st.sidebar.title("Navigation")
22
+ page = st.sidebar.radio("Choose a step:", [
23
+ "1. Introduction",
24
+ "2. Write & Compile Contract",
25
+ "3. Generate Keys",
26
+ "4. Interact with StarkNet"
27
+ ])
28
 
29
+ # Page 1: Introduction
30
+ if page == "1. Introduction":
31
+ st.header("Introduction to StarkNet Development")
32
+ st.write("""
33
+ StarkNet is a permissionless decentralized ZK-Rollup operating as an L2 network over Ethereum.
34
+ This application helps you with the full development workflow:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ 1. **Write and compile Cairo contracts** - Create smart contracts with Cairo language
37
+ 2. **Generate key pairs and addresses** - Create cryptographic keys for StarkNet
38
+ 3. **Interact with StarkNet** - Deploy contracts and interact with the network
 
 
 
 
39
 
40
+ Use the sidebar to navigate through different steps of the workflow.
41
+ """)
42
 
43
+ st.info("This is a development tool. For production use, please ensure proper security measures.")
 
 
 
 
 
 
44
 
45
+ # Page 2: Write & Compile Contract
46
+ elif page == "2. Write & Compile Contract":
47
+ st.header("Write & Compile Cairo Contract")
48
 
49
+ # Default example contract
50
+ default_contract = """
51
+ %lang cairo
52
 
53
  @external
54
  func transfer{syscall_ptr: felt*, range_check_ptr}(
 
56
  to_address: felt,
57
  amount: felt
58
  ) -> (success: felt):
59
+ # This is just a simple simulated transfer function
60
+ # In a real application, you would need to perform balance checks and state updates
61
+ return (1) # Return success
62
  end
63
 
64
  @view
65
  func get_balance{syscall_ptr: felt*, range_check_ptr}(
66
  address: felt
67
  ) -> (balance: felt):
68
+ # This is just a simple simulated balance query function
69
+ # In a real application, you would read the actual balance from storage
70
+ return (1000) # Return simulated balance
71
  end
72
  """
73
 
74
+ # Contract editor
75
+ st.subheader("Contract Editor")
76
+ contract_code = st.text_area("Edit your Cairo contract:", default_contract, height=400)
77
 
78
+ # Compile button
79
+ if st.button("Compile Contract"):
80
+ try:
81
+ # Save the contract to a file
82
+ with open('token_contract.cairo', 'w') as file:
83
+ file.write(contract_code)
84
 
85
+ # Run the compilation command
86
+ with st.spinner("Compiling..."):
87
+ result = subprocess.run(
88
+ ["cairo-compile", "token_contract.cairo", "--output", "token_compiled.json"],
89
+ capture_output=True,
90
+ text=True
91
+ )
92
+
93
+ if result.returncode == 0:
94
+ st.success("Contract compiled successfully!")
95
+
96
+ # Display compilation output
97
+ with open("token_compiled.json", "r") as f:
98
+ compiled_json = json.load(f)
99
 
100
+ # Allow downloading the compiled contract
101
+ st.download_button(
102
+ label="Download Compiled Contract",
103
+ data=json.dumps(compiled_json, indent=2),
104
+ file_name="token_compiled.json",
105
+ mime="application/json"
106
+ )
107
  else:
108
+ st.error(f"Compilation failed: {result.stderr}")
109
+ except Exception as e:
110
+ st.error(f"Error during compilation: {str(e)}")
111
 
112
+ # Page 3: Generate Keys
113
+ elif page == "3. Generate Keys":
114
+ st.header("Generate StarkNet Keys")
115
+
116
+ col1, col2 = st.columns(2)
117
+
118
+ with col1:
119
+ st.subheader("Key Generation")
120
+
121
+ # Network selection
122
+ st.write("Select StarkNet Network:")
123
+ network_options = {
124
+ "Goerli Testnet": "GOERLI",
125
+ "Sepolia Testnet": "SEPOLIA",
126
+ "Mainnet": "MAINNET",
127
+ "Custom": "CUSTOM"
128
+ }
129
+ network = st.selectbox("Network", list(network_options.keys()))
130
+
131
+ if network == "Custom":
132
+ chain_id_value = st.number_input("Enter Chain ID value:", value=1536727068981429685321)
133
+ else:
134
+ try:
135
+ chain_id_attr = getattr(StarknetChainId, network_options[network])
136
+ chain_id_value = chain_id_attr.value
137
+ except (AttributeError, KeyError):
138
+ chain_id_value = 1536727068981429685321
139
+ st.warning(f"Using default chain ID: {chain_id_value}")
140
+
141
+ if st.button("Generate New Keys"):
142
+ with st.spinner("Generating..."):
143
+ # Generate a random private key
144
+ private_key = secrets.randbits(251)
145
+ private_key_hex = hex(private_key)
146
+
147
+ # Create key pair
148
+ key_pair = KeyPair.from_private_key(private_key)
149
+
150
+ # Get the public key
151
+ public_key = key_pair.public_key
152
+ public_key_hex = hex(public_key)
153
+
154
+ # Create account object
155
+ account = Account(
156
+ address=0, # Will be populated after deployment
157
+ client=None, # No client needed in this example
158
+ key_pair=key_pair,
159
+ chain=chain_id_value
160
+ )
161
+
162
+ # Get the account address
163
+ address = account.address
164
+
165
+ # Store in session state
166
+ st.session_state['private_key'] = private_key_hex
167
+ st.session_state['public_key'] = public_key_hex
168
+ st.session_state['address'] = hex(address)
169
+ st.session_state['chain_id'] = chain_id_value
170
+
171
+ st.success("Keys generated successfully!")
172
 
173
+ with col2:
174
+ st.subheader("Key Information")
175
+
176
+ if 'private_key' in st.session_state:
177
+ st.markdown("**Private Key:**")
178
+ st.code(st.session_state['private_key'])
179
 
180
+ st.markdown("**Public Key:**")
181
+ st.code(st.session_state['public_key'])
182
 
183
+ st.markdown("**Address:**")
184
+ st.code(st.session_state['address'])
 
 
 
 
 
 
185
 
186
+ st.markdown("**Chain ID:**")
187
+ st.code(str(st.session_state['chain_id']))
 
 
 
188
 
189
+ # Create downloadable key file
190
+ key_info = f"""Private Key: {st.session_state['private_key']}
191
+ Public Key: {st.session_state['public_key']}
192
+ Address: {st.session_state['address']}
193
+ Chain ID: {st.session_state['chain_id']}
194
+ """
195
  st.download_button(
196
+ label="Download Key Information",
197
+ data=key_info,
198
  file_name="starknet_keys.txt",
199
  mime="text/plain"
200
  )
201
+
202
+ st.warning("⚠️ Keep your private key secure! Never share it with anyone.")
203
+ else:
204
+ st.info("Generate keys to see the information here.")
 
 
 
 
 
 
205
 
206
+ # Page 4: Interact with StarkNet
207
+ elif page == "4. Interact with StarkNet":
208
+ st.header("Interact with StarkNet")
209
 
210
+ st.info("""
211
+ This section provides sample code for interacting with StarkNet.
212
+ For actual interaction, you would need:
 
 
 
 
 
213
 
214
+ 1. A deployed contract address
215
+ 2. The contract ABI
216
+ 3. A funded account
217
 
218
+ Below is sample code that you can modify for your needs.
219
+ """)
220
 
221
+ interaction_code = """
222
+ # StarkNet Interaction Example
223
+ from starknet_py.net.gateway_client import GatewayClient
224
+ from starknet_py.net.models import StarknetChainId
225
+ from starknet_py.contract import Contract
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
 
227
+ # Set up StarkNet client (using Goerli testnet)
228
+ client = GatewayClient(net="goerli") # Or "mainnet" for the mainnet
 
 
 
229
 
230
+ # Replace with your contract's address and ABI
231
+ contract_address = 0x123456789 # Replace with the real contract address
232
+ contract_abi = [...] # Contract's ABI, typically obtained from compilation output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
 
234
+ # Load the deployed contract
235
  contract = Contract(
236
+ address=contract_address,
237
+ abi=contract_abi,
238
+ client=client,
239
  )
240
 
241
+ # Replace with your account information
242
+ private_key = "YOUR_PRIVATE_KEY"
243
+ key_pair = KeyPair.from_private_key(int(private_key, 16))
244
+ account = Account(
245
+ address=0x..., # Your account address
246
+ client=client,
247
+ key_pair=key_pair,
248
+ chain=StarknetChainId.GOERLI
249
  )
 
 
 
 
250
 
251
+ # Example: Call a contract function
252
+ async def transfer_tokens():
253
+ response = await account.execute(
254
+ calls=[
255
+ contract.functions["transfer"].prepare(
256
+ from_address=account.address,
257
+ to_address=0x987654321, # Receiver address
258
+ amount=100
259
+ )
260
+ ]
261
+ )
262
+ print(f"Transaction hash: {response.transaction_hash}")
263
+
264
+ # Example: Query contract state
265
+ async def check_balance(address):
266
+ balance = await contract.functions["get_balance"].call(
267
+ address=address
268
+ )
269
+ print(f"Balance: {balance.balance}")
270
+ """
271
+
272
+ st.code(interaction_code, language="python")
273
+
274
+ st.subheader("Resources")
275
+ st.markdown("""
276
+ - [StarkNet Documentation](https://docs.starknet.io/)
277
+ - [Cairo Programming Language](https://cairo-lang.org/)
278
+ - [starknet-py Library](https://github.com/software-mansion/starknet.py)
279
+ """)
280
+
281
+ st.sidebar.markdown("---")
282
+ st.sidebar.info("This application is for educational purposes. Always follow best security practices when working with cryptographic keys.")