Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import secrets | |
| import hashlib | |
| import os | |
| import subprocess | |
| import json | |
| from starknet_py.net.account.account import Account | |
| from starknet_py.net.models import StarknetChainId | |
| from starknet_py.net.signer.stark_curve_signer import KeyPair | |
| st.set_page_config( | |
| page_title="StarkNet Development Toolkit", | |
| page_icon="🌟", | |
| layout="wide" | |
| ) | |
| st.title("StarkNet Development Toolkit") | |
| st.markdown("A complete workflow for StarkNet development including contract compilation, key generation, and more.") | |
| # Sidebar for navigation | |
| st.sidebar.title("Navigation") | |
| page = st.sidebar.radio("Choose a step:", [ | |
| "1. Introduction", | |
| "2. Write & Compile Contract", | |
| "3. Generate Keys", | |
| "4. Interact with StarkNet" | |
| ]) | |
| # Page 1: Introduction | |
| if page == "1. Introduction": | |
| st.header("Introduction to StarkNet Development") | |
| st.write(""" | |
| StarkNet is a permissionless decentralized ZK-Rollup operating as an L2 network over Ethereum. | |
| This application helps you with the full development workflow: | |
| 1. **Write and compile Cairo contracts** - Create smart contracts with Cairo language | |
| 2. **Generate key pairs and addresses** - Create cryptographic keys for StarkNet | |
| 3. **Interact with StarkNet** - Deploy contracts and interact with the network | |
| Use the sidebar to navigate through different steps of the workflow. | |
| """) | |
| st.info("This is a development tool. For production use, please ensure proper security measures.") | |
| # Page 2: Write & Compile Contract | |
| elif page == "2. Write & Compile Contract": | |
| st.header("Write & Compile Cairo Contract") | |
| # Default example contract | |
| default_contract = """ | |
| %lang cairo | |
| @external | |
| func transfer{syscall_ptr: felt*, range_check_ptr}( | |
| from_address: felt, | |
| to_address: felt, | |
| amount: felt | |
| ) -> (success: felt): | |
| # This is just a simple simulated transfer function | |
| # In a real application, you would need to perform balance checks and state updates | |
| return (1) # Return success | |
| end | |
| @view | |
| func get_balance{syscall_ptr: felt*, range_check_ptr}( | |
| address: felt | |
| ) -> (balance: felt): | |
| # This is just a simple simulated balance query function | |
| # In a real application, you would read the actual balance from storage | |
| return (1000) # Return simulated balance | |
| end | |
| """ | |
| # Contract editor | |
| st.subheader("Contract Editor") | |
| contract_code = st.text_area("Edit your Cairo contract:", default_contract, height=400) | |
| # Compile button | |
| if st.button("Compile Contract"): | |
| try: | |
| # Save the contract to a file | |
| with open('token_contract.cairo', 'w') as file: | |
| file.write(contract_code) | |
| # Run the compilation command | |
| with st.spinner("Compiling..."): | |
| result = subprocess.run( | |
| ["cairo-compile", "token_contract.cairo", "--output", "token_compiled.json"], | |
| capture_output=True, | |
| text=True | |
| ) | |
| if result.returncode == 0: | |
| st.success("Contract compiled successfully!") | |
| # Display compilation output | |
| with open("token_compiled.json", "r") as f: | |
| compiled_json = json.load(f) | |
| # Allow downloading the compiled contract | |
| st.download_button( | |
| label="Download Compiled Contract", | |
| data=json.dumps(compiled_json, indent=2), | |
| file_name="token_compiled.json", | |
| mime="application/json" | |
| ) | |
| else: | |
| st.error(f"Compilation failed: {result.stderr}") | |
| except Exception as e: | |
| st.error(f"Error during compilation: {str(e)}") | |
| # Page 3: Generate Keys | |
| elif page == "3. Generate Keys": | |
| st.header("Generate StarkNet Keys") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.subheader("Key Generation") | |
| # Network selection | |
| st.write("Select StarkNet Network:") | |
| network_options = { | |
| "Goerli Testnet": "GOERLI", | |
| "Sepolia Testnet": "SEPOLIA", | |
| "Mainnet": "MAINNET", | |
| "Custom": "CUSTOM" | |
| } | |
| network = st.selectbox("Network", list(network_options.keys())) | |
| if network == "Custom": | |
| chain_id_value = st.number_input("Enter Chain ID value:", value=1536727068981429685321) | |
| else: | |
| try: | |
| chain_id_attr = getattr(StarknetChainId, network_options[network]) | |
| chain_id_value = chain_id_attr.value | |
| except (AttributeError, KeyError): | |
| chain_id_value = 1536727068981429685321 | |
| st.warning(f"Using default chain ID: {chain_id_value}") | |
| if st.button("Generate New Keys"): | |
| with st.spinner("Generating..."): | |
| # Generate a random private key | |
| private_key = secrets.randbits(251) | |
| private_key_hex = hex(private_key) | |
| # Create key pair | |
| key_pair = KeyPair.from_private_key(private_key) | |
| # Get the public key | |
| public_key = key_pair.public_key | |
| public_key_hex = hex(public_key) | |
| # Create account object | |
| account = Account( | |
| address=0, # Will be populated after deployment | |
| client=None, # No client needed in this example | |
| key_pair=key_pair, | |
| chain=chain_id_value | |
| ) | |
| # Get the account address | |
| address = account.address | |
| # Store in session state | |
| st.session_state['private_key'] = private_key_hex | |
| st.session_state['public_key'] = public_key_hex | |
| st.session_state['address'] = hex(address) | |
| st.session_state['chain_id'] = chain_id_value | |
| st.success("Keys generated successfully!") | |
| with col2: | |
| st.subheader("Key Information") | |
| if 'private_key' in st.session_state: | |
| st.markdown("**Private Key:**") | |
| st.code(st.session_state['private_key']) | |
| st.markdown("**Public Key:**") | |
| st.code(st.session_state['public_key']) | |
| st.markdown("**Address:**") | |
| st.code(st.session_state['address']) | |
| st.markdown("**Chain ID:**") | |
| st.code(str(st.session_state['chain_id'])) | |
| # Create downloadable key file | |
| key_info = f"""Private Key: {st.session_state['private_key']} | |
| Public Key: {st.session_state['public_key']} | |
| Address: {st.session_state['address']} | |
| Chain ID: {st.session_state['chain_id']} | |
| """ | |
| st.download_button( | |
| label="Download Key Information", | |
| data=key_info, | |
| file_name="starknet_keys.txt", | |
| mime="text/plain" | |
| ) | |
| st.warning("⚠️ Keep your private key secure! Never share it with anyone.") | |
| else: | |
| st.info("Generate keys to see the information here.") | |
| # Page 4: Interact with StarkNet | |
| elif page == "4. Interact with StarkNet": | |
| st.header("Interact with StarkNet") | |
| st.info(""" | |
| This section provides sample code for interacting with StarkNet. | |
| For actual interaction, you would need: | |
| 1. A deployed contract address | |
| 2. The contract ABI | |
| 3. A funded account | |
| Below is sample code that you can modify for your needs. | |
| """) | |
| interaction_code = """ | |
| # StarkNet Interaction Example | |
| from starknet_py.net.gateway_client import GatewayClient | |
| from starknet_py.net.models import StarknetChainId | |
| from starknet_py.contract import Contract | |
| # Set up StarkNet client (using Goerli testnet) | |
| client = GatewayClient(net="goerli") # Or "mainnet" for the mainnet | |
| # Replace with your contract's address and ABI | |
| contract_address = 0x123456789 # Replace with the real contract address | |
| contract_abi = [...] # Contract's ABI, typically obtained from compilation output | |
| # Load the deployed contract | |
| contract = Contract( | |
| address=contract_address, | |
| abi=contract_abi, | |
| client=client, | |
| ) | |
| # Replace with your account information | |
| private_key = "YOUR_PRIVATE_KEY" | |
| key_pair = KeyPair.from_private_key(int(private_key, 16)) | |
| account = Account( | |
| address=0x..., # Your account address | |
| client=client, | |
| key_pair=key_pair, | |
| chain=StarknetChainId.GOERLI | |
| ) | |
| # Example: Call a contract function | |
| async def transfer_tokens(): | |
| response = await account.execute( | |
| calls=[ | |
| contract.functions["transfer"].prepare( | |
| from_address=account.address, | |
| to_address=0x987654321, # Receiver address | |
| amount=100 | |
| ) | |
| ] | |
| ) | |
| print(f"Transaction hash: {response.transaction_hash}") | |
| # Example: Query contract state | |
| async def check_balance(address): | |
| balance = await contract.functions["get_balance"].call( | |
| address=address | |
| ) | |
| print(f"Balance: {balance.balance}") | |
| """ | |
| st.code(interaction_code, language="python") | |
| st.subheader("Resources") | |
| st.markdown(""" | |
| - [StarkNet Documentation](https://docs.starknet.io/) | |
| - [Cairo Programming Language](https://cairo-lang.org/) | |
| - [starknet-py Library](https://github.com/software-mansion/starknet.py) | |
| """) | |
| st.sidebar.markdown("---") | |
| st.sidebar.info("This application is for educational purposes. Always follow best security practices when working with cryptographic keys.") |