import streamlit as st from utils.transfer_utils import transfer_apt_sync from components.auth_component import one_round_auth from pages import app # Registration Page st.header("๐Ÿ“ Registration") if not app.wallet: st.error("โŒ Please connect a wallet first") st.info("๐Ÿ‘ˆ Go to 'Import/Generate Wallet' to get started") st.stop() if app.is_registered: st.success("โœ… You are already registered!") st.info("๐Ÿ‘ˆ Go to 'Authentication' to verify your 1P secret") st.stop() st.markdown(""" ### Registration Process: 1. **Select your 1P secret** - Choose one UTF-8 character elegantly 2. **Configure direction mapping** - Set your color-to-direction preferences 3. **Authenticate yourself** - Verify your 1P secret with a quick challenge 4. **Transfer minimum 1 APT** - Funds will be held in our secure system wallet 5. **Complete registration** - Your wallet will be registered for 1P authentication """) # Step 1: UTF-8 Character Selection st.markdown("---") st.subheader("๐ŸŽจ Step 1: Select Your 1P Secret") st.markdown("Choose **one character** that will be your secret. No keyboard typing required!") # Language/Category filters col1, col2 = st.columns(2) with col1: category_type = st.selectbox( "Category Type", options=["Emojis & Symbols", "Languages", "All Categories"], index=0, help="Filter by type of character categories" ) # Dynamically set options based on category type if category_type == "Emojis & Symbols": category_options = ['emojis', 'hearts', 'nature', 'food', 'animals', 'travel', 'sports', 'tech', 'music', 'weather', 'zodiac', 'numbers', 'symbols', 'ascii'] elif category_type == "Languages": category_options = ['japanese', 'korean', 'chinese', 'arabic', 'cyrillic', 'ascii'] else: category_options = list(DOMAINS.keys()) selected_categories = st.multiselect( "Character Categories", options=category_options, default=['emojis'] if category_type == "Emojis & Symbols" else ['ascii'] if category_type == "Languages" else ['emojis'], help="Select which types of characters to show" ) with col2: col2_1, col2_2 = st.columns(2) with col2_1: chars_per_row = st.slider("Characters per row", 5, 20, 10) with col2_2: show_unicode = st.checkbox("Show Unicode codes", False) search_term = st.text_input("Search (emoji description or character)", "", placeholder="heart, food, smile, etc.", help="Filter characters by description") # Build character set based on selection available_chars = "" for category in selected_categories: available_chars += DOMAINS[category] if not available_chars: st.warning("Please select at least one character category") st.stop() # Apply search filter if provided chars_list = list(set(available_chars)) # Remove duplicates if search_term: # Simple filtering mechanism search_term = search_term.lower() # Define some common emoji descriptions for better search emoji_descriptions = { 'smile': '๐Ÿ˜€๐Ÿ˜ƒ๐Ÿ˜„๐Ÿ˜๐Ÿ˜†', 'laugh': '๐Ÿ˜‚๐Ÿคฃ', 'heart': 'โค๏ธ๐Ÿ’–๐Ÿ’๐Ÿ’˜๐Ÿ’—๐Ÿ’“๐Ÿ’•๐Ÿ’ž๐Ÿ’œ๐Ÿงก๐Ÿ’›๐Ÿ’š๐Ÿ’™', 'food': '๐ŸŽ๐ŸŒ๐Ÿ‡๐Ÿ“๐Ÿˆ๐Ÿ‰๐ŸŠ๐Ÿ‹๐Ÿฅญ๐Ÿ‘๐Ÿ’๐Ÿฅ๐Ÿ๐Ÿฅฅ๐Ÿ…๐Ÿฅ‘๐Ÿ†๐Ÿฅ”๐Ÿฅ•๐ŸŒฝ', 'animal': '๐Ÿถ๐Ÿฑ๐Ÿญ๐Ÿน๐Ÿฐ๐ŸฆŠ๐Ÿป๐Ÿผ๐Ÿจ๐Ÿฆ๐Ÿฏ๐Ÿฎ๐Ÿท๐Ÿธ๐Ÿต๐Ÿ”', 'flower': '๐ŸŒธ๐ŸŒบ๐ŸŒป๐ŸŒท๐ŸŒน๐ŸŒผ', 'star': 'โญ๐ŸŒŸ๐Ÿ’ซโœจ', 'face': '๐Ÿ˜€๐Ÿ˜ƒ๐Ÿ˜„๐Ÿ˜๐Ÿ˜†๐Ÿ˜…๐Ÿ˜‚๐Ÿคฃ๐Ÿ˜Š๐Ÿ˜‡๐Ÿ™‚๐Ÿ™ƒ๐Ÿ˜‰๐Ÿ˜Œ๐Ÿ˜', 'hand': '๐Ÿ‘๐Ÿ‘Ž๐Ÿ‘ŒโœŒ๏ธ๐Ÿคž๐ŸคŸ๐Ÿค˜๐Ÿ‘ŠโœŠ๐Ÿค›๐Ÿคœ๐Ÿ‘', 'music': '๐ŸŽต๐ŸŽถ๐ŸŽธ๐ŸŽน๐ŸŽท๐ŸŽบ๐ŸŽป๐Ÿฅ๐ŸŽผ', 'sport': 'โšฝโšพ๐Ÿ€๐Ÿ๐Ÿˆ๐Ÿ‰๐ŸŽพ๐Ÿ“๐Ÿธ', 'travel': 'โœˆ๏ธ๐Ÿš†๐Ÿš‚๐Ÿš„๐Ÿš˜๐Ÿšฒ', 'weather': 'โ˜€๏ธ๐ŸŒค๏ธโ›…๐ŸŒฅ๏ธโ˜๏ธ๐ŸŒฆ๏ธ๐ŸŒง๏ธโ›ˆ๏ธ' } filtered_chars = [] for char in chars_list: # Check if char is in any of the emoji description groups that match the search term in_description = False for desc, emoji_group in emoji_descriptions.items(): if desc.lower().find(search_term) >= 0 and char in emoji_group: in_description = True break # Add char if it matches search if in_description or char.lower() == search_term.lower(): filtered_chars.append(char) chars_list = filtered_chars if filtered_chars else chars_list # Sort the characters chars_list.sort() # Create a pagination system for large character sets chars_per_page = chars_per_row * 5 # 5 rows per page total_chars = len(chars_list) total_pages = (total_chars + chars_per_page - 1) // chars_per_page # Ceiling division # Only show pagination if needed if total_pages > 1: col1, col2, col3 = st.columns([1, 3, 1]) with col2: page_num = st.select_slider("Page", options=list(range(1, total_pages + 1)), value=1) else: page_num = 1 start_idx = (page_num - 1) * chars_per_page end_idx = min(start_idx + chars_per_page, total_chars) # Display character selection grid st.markdown(f"**Available Characters:** ({total_chars} characters found)") visible_chars = chars_list[start_idx:end_idx] # Create grid display rows = [visible_chars[i:i + chars_per_row] for i in range(0, len(visible_chars), chars_per_row)] selected_secret = None for row_idx, row in enumerate(rows): cols = st.columns(len(row)) for col_idx, char in enumerate(row): with cols[col_idx]: unicode_info = f"\\nU+{ord(char):04X}" if show_unicode else "" if st.button(f"{char}{unicode_info}", key=f"char_{row_idx}_{col_idx}_p{page_num}", use_container_width=True): selected_secret = char app.selected_secret = char app.save_to_session() st.rerun() # Show recently used characters for quick selection if not app.selected_secret and (app.recent_characters or app.favorite_characters): st.markdown("---") st.subheader("โญ Quick Selection") # Show favorites if available if app.favorite_characters: st.markdown("**Favorite Characters:**") fav_cols = st.columns(min(10, len(app.favorite_characters))) for idx, char in enumerate(app.favorite_characters): with fav_cols[idx % len(fav_cols)]: if st.button(f"{char}", key=f"fav_{idx}", use_container_width=True): app.selected_secret = char app.save_to_session() st.rerun() # Show recent characters if available if app.recent_characters: st.markdown("**Recently Used:**") recent_cols = st.columns(min(10, len(app.recent_characters))) for idx, char in enumerate(app.recent_characters): with recent_cols[idx % len(recent_cols)]: if st.button(f"{char}", key=f"recent_{idx}", use_container_width=True): app.selected_secret = char # Add to favorites with recent_cols[idx % len(recent_cols)]: if st.button("โญ", key=f"fav_add_{idx}", help="Add to favorites"): if char not in app.favorite_characters: app.favorite_characters.append(char) if len(app.favorite_characters) > 10: app.favorite_characters.pop(0) # Remove oldest if over limit app.save_to_session() st.rerun() # Show selected secret if app.selected_secret: st.success(f"โœ… Selected secret: **{app.selected_secret}** (U+{ord(app.selected_secret):04X})") # Add selected character to recent list if not already there if app.selected_secret not in app.recent_characters: app.recent_characters.append(app.selected_secret) # Keep only the last 10 characters if len(app.recent_characters) > 10: app.recent_characters.pop(0) app.save_to_session() # Option to add to favorites col1, col2 = st.columns([3, 1]) with col2: if app.selected_secret not in app.favorite_characters: if st.button("โญ Add to Favorites"): app.favorite_characters.append(app.selected_secret) if len(app.favorite_characters) > 10: app.favorite_characters.pop(0) # Remove oldest if over limit app.save_to_session() st.rerun() else: if st.button("โŒ Remove from Favorites"): app.favorite_characters.remove(app.selected_secret) app.save_to_session() st.rerun() # Step 2: Direction Mapping Configuration if app.selected_secret: st.markdown("---") st.subheader("๐Ÿงญ Step 2: Configure Direction Mapping") st.markdown("Set your preferred directions for each color. This will be used during authentication.") col1, col2 = st.columns(2) direction_mapping = {} with col1: st.markdown("**Color โ†’ Direction Mapping:**") for color in COLORS: direction_mapping[color] = st.selectbox( f"{color.title()} โ†’", options=DIRECTIONS, key=f"direction_{color}", index=DIRECTIONS.index(DIRECTIONS[COLORS.index(color)]) # Default mapping ) with col2: st.markdown("**Preview:**") for color, direction in direction_mapping.items(): emoji_map = {"Up": "โฌ†๏ธ", "Down": "โฌ‡๏ธ", "Left": "โฌ…๏ธ", "Right": "โžก๏ธ", "Skip": "โญ๏ธ"} st.text(f"{color.title()}: {direction} {emoji_map[direction]}") app.direction_mapping = direction_mapping app.save_to_session() # Step 3: Authentication if app.selected_secret and app.direction_mapping: st.markdown("---") st.subheader("๐Ÿ” Step 3: Authenticate Yourself") st.markdown("""Verify your identity using the 1P visual grid system. This ensures you remember your secret character and color-to-direction mapping before proceeding with fund transfer.""") # Show authentication challenge using the component auth_success = one_round_auth( secret=app.selected_secret, direction_mapping=app.direction_mapping, colors=COLORS, direction_map=DIRECTION_MAP, domains=DOMAINS, session_key="registration_auth" ) if not auth_success: # If auth is not completed or failed, stop here if app.registration_auth and app.registration_auth.get("completed"): if not app.registration_auth.get("success"): st.error("โŒ Authentication failed! Please try again.") if st.button("๐Ÿ”„ Try Again", key="auth_retry"): # Reset auth state app.registration_auth = { 'started': False, 'completed': False, 'success': False, 'grid_html': None, 'expected': None } app.save_to_session() st.rerun() st.stop() st.success("โœ… Authentication successful!") # Step 4: Balance Transfer if app.selected_secret and app.direction_mapping and app.registration_auth and app.registration_auth.get("completed") and app.registration_auth.get("success"): st.markdown("---") st.subheader("๐Ÿ’ฐ Step 4: Transfer Funds for Registration") st.markdown("**Why transfer funds?**") st.markdown(""" - Transfers 1 APT minimum to register for the 1P system - Your funds are held securely in our system wallet - Transactions are processed through our secure backend - Your private key is never exposed after registration """) # Check current balance automatically with st.spinner("Checking wallet balance..."): try: # Try to use the sync helper method apt_balance = app.get_account_balance_sync(app.wallet.address()) # Display balance with colorful metric col1, col2 = st.columns(2) with col1: st.metric("Current Wallet Balance", f"{apt_balance} APT") with col2: if apt_balance >= 1.0: st.success("โœ… Sufficient balance for registration") else: st.error("โŒ Insufficient balance. Need at least 1 APT.") st.warning("Please use the faucet in the wallet setup page.") st.stop() # Add refresh button if st.button("๐Ÿ”„ Refresh Balance", type="secondary"): st.rerun() except Exception as e: st.error(f"Balance check error: {str(e)}") st.warning("Unable to check balance automatically. You can proceed if you know you have sufficient funds (at least 1 APT).") # Add manual balance check option if st.button("Try Again", type="secondary"): st.rerun() # Provide option to continue anyway st.info("If you're certain you have at least 1 APT, you can continue with the registration.") # Option to proceed anyway if not st.checkbox("I understand the risks and want to proceed anyway"): st.stop() # Transfer amount selection col1, col2 = st.columns(2) with col1: transfer_amount = st.number_input( "Transfer Amount (APT)", min_value=1.0, max_value=100.0, value=1.0, step=0.1, help="Minimum 1 APT required" ) with col2: st.markdown("
", unsafe_allow_html=True) # Spacing leave_for_gas = st.checkbox("Leave 0.1 APT for gas fees", value=True) # Step 5: Complete Registration st.markdown("---") st.subheader("โœ… Step 5: Complete Registration") st.warning("โš ๏ธ **Final Check:**") st.markdown(f""" - **Secret Character:** {app.selected_secret} - **Direction Mapping:** {len(app.direction_mapping)} colors configured - **Transfer Amount:** {transfer_amount} APT - **From Wallet:** `{app.wallet.address()[:10]}...` """) st.error("๐Ÿ”’ **Important:** After registration, your wallet's private key will be securely handled by our system. Make sure you're ready to proceed.") confirm_registration = st.checkbox("I understand and want to proceed with registration") if confirm_registration and st.button("๐Ÿš€ Complete Registration", type="primary"): with st.spinner("Processing registration..."): try: # Check user wallet balance first apt_balance = app.get_account_balance_sync(app.wallet.address()) if apt_balance < transfer_amount: st.error(f"โŒ Insufficient balance: You have {apt_balance} APT but are trying to transfer {transfer_amount} APT") st.warning("Please get more APT from the faucet or reduce the transfer amount.") st.stop() # Use our abstracted transfer function with st.spinner("Creating and processing transaction..."): success, txn_hash, error_msg = transfer_apt_sync( sender_account=app.wallet, recipient_address=SYSTEM_WALLET_ADDRESS, amount_apt=transfer_amount ) if not success: st.error(f"Transaction failed: {error_msg}") st.warning("Please check your balance and try again.") st.stop() # Mark as registered and record the transaction app.is_registered = True # Record transaction in our history app.add_transaction( txn_hash=txn_hash, sender=str(app.wallet.address()), recipient=SYSTEM_WALLET_ADDRESS, amount=transfer_amount, is_credit=False, status="completed", description="1P Wallet Registration" ) # Persist changes to session app.save_to_session() st.success("๐ŸŽ‰ Registration completed successfully!") st.success(f"โœ… Transaction Hash: `{txn_hash}`") st.info("**Next:** Go to 'Authentication' to verify your 1P secret") st.markdown("๐Ÿ“‹ You can view this transaction in your **Transaction History** page") # Show registration summary with st.expander("Registration Summary", expanded=True): st.markdown(f""" - **Wallet:** `{app.wallet.address()}` - **Secret:** {app.selected_secret} (U+{ord(app.selected_secret):04X}) - **Amount Transferred:** {transfer_amount} APT - **Transaction:** `{txn_hash}` - **System Wallet:** `{SYSTEM_WALLET_ADDRESS}` """) except Exception as e: st.error(f"โŒ Registration failed: {str(e)}") st.error("Please check your balance and try again")