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