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.")