fugthchat commited on
Commit
2c7fac5
Β·
verified Β·
1 Parent(s): 64d5cfa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +145 -166
app.py CHANGED
@@ -8,11 +8,14 @@ import firebase_admin
8
  from firebase_admin import credentials, firestore
9
 
10
  # --- PAGE CONFIG ---
11
- st.set_page_config(page_title="Vivara Command v2", page_icon="🦁", layout="wide")
12
- st.title("🦁 Vivara Ecosystem Command")
13
 
14
- # --- 1. FIREBASE CONNECTION ---
15
- # Checks if connected, otherwise loads from Secrets
 
 
 
 
16
  if not firebase_admin._apps:
17
  key_json = os.getenv("FIREBASE_SERVICE_ACCOUNT")
18
  if key_json:
@@ -20,202 +23,178 @@ if not firebase_admin._apps:
20
  cred_dict = json.loads(key_json)
21
  cred = credentials.Certificate(cred_dict)
22
  firebase_admin.initialize_app(cred)
23
- st.toast("πŸ”₯ Firebase Connected (Admin Mode)", icon="βœ…")
24
  except Exception as e:
25
- st.error(f"Firebase Key Error: {e}")
26
  else:
27
- st.warning("⚠️ Add 'FIREBASE_SERVICE_ACCOUNT' secret to enable User Management.")
28
 
29
  try:
30
  db = firestore.client()
31
  except:
32
  db = None
33
 
34
- # --- SIDEBAR CONFIG ---
35
  with st.sidebar:
36
- st.header("βš™οΈ Settings")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  rpc_url = st.text_input("RPC URL", value="https://polygon-rpc.com")
38
  chain_id = st.number_input("Chain ID", value=137)
39
 
40
- private_key = os.getenv("PRIVATE_KEY")
41
- if private_key:
42
- st.success("πŸ”‘ Wallet Key Loaded")
 
43
  else:
44
- st.error("⚠️ Add 'PRIVATE_KEY' secret")
45
 
46
- # --- TABS ---
47
- tab1, tab2, tab3 = st.tabs(["πŸ‘₯ User Manager", "πŸ“§ Newsletter & Growth", "βš’οΈ Solidity Forge"])
48
 
49
- # ==========================================
50
- # TAB 1: USER MANAGER (TIERS)
51
- # ==========================================
52
- with tab1:
53
- st.header("User Database")
54
-
55
- if db:
56
- users_ref = db.collection("users")
57
- all_users = list(users_ref.stream())
58
-
59
- # Calculate Stats
60
- total_users = len(all_users)
61
- founders = 0
62
- alphas = 0
63
- betas = 0
64
-
65
- user_data = []
66
- for doc in all_users:
67
- u = doc.to_dict()
68
- inv = u.get("inventory", [])
69
- rank = u.get("redeem_rank", "-")
70
-
71
- status = "User"
72
- if "FOUNDER" in inv:
73
- founders += 1
74
- status = "πŸ† GOLD"
75
- elif "ALPHA" in inv:
76
- alphas += 1
77
- status = "πŸ₯ˆ SILVER"
78
- elif "BETA" in inv:
79
- betas += 1
80
- status = "πŸ₯‰ BRONZE"
81
-
82
- user_data.append({
83
- "ID": doc.id[:6],
84
- "Name": u.get("displayName", "Unknown"),
85
- "Email": u.get("email", "-"),
86
- "Status": status,
87
- "Rank": rank
88
- })
89
 
90
- # Display Metrics
91
- c1, c2, c3, c4 = st.columns(4)
92
- c1.metric("Total Users", total_users)
93
- c2.metric("πŸ† Gold Founders", founders)
94
- c3.metric("πŸ₯ˆ Silver Alphas", alphas)
95
- c4.metric("Revenue (Est)", f"${(founders + alphas + betas) * 5}")
96
-
97
- st.divider()
98
-
99
- # User Table
100
- st.subheader("User List")
101
- df_users = pd.DataFrame(user_data)
102
- st.dataframe(df_users, use_container_width=True)
103
-
104
- # Manual Grant Tool
105
- st.divider()
106
- st.subheader("πŸ› οΈ Manual Grant (Bypass Payment)")
107
- with st.form("grant_form"):
108
- c_email, c_tier = st.columns([2, 1])
109
- target_email = c_email.text_input("User Email")
110
- tier_select = c_tier.selectbox("Tier", ["FOUNDER", "ALPHA", "BETA"])
111
-
112
- if st.form_submit_button("Grant Access"):
113
- # Search for user
114
- q = users_ref.where("email", "==", target_email).limit(1).get()
115
- if q:
116
- target_doc = q[0].reference
117
- # Update Inventory
118
- target_doc.update({
119
- "inventory": firestore.ArrayUnion([tier_select, "LICENSE_V1", "MANUAL_GRANT"]),
120
- "redeem_rank": 0 # Manual grants get Rank 0
121
- })
122
- st.success(f"Granted {tier_select} to {target_email}")
123
- else:
124
- st.error("User email not found. Tell them to sign up first.")
125
 
126
  # ==========================================
127
- # TAB 2: NEWSLETTER (MARKETING)
128
  # ==========================================
129
- with tab2:
130
- st.header("πŸ“§ Email List")
131
 
132
- if db:
133
- news_ref = db.collection("newsletters")
134
- emails = list(news_ref.order_by("timestamp", direction=firestore.Query.DESCENDING).stream())
135
-
136
- st.metric("Total Subscribers", len(emails))
137
-
138
- if len(emails) > 0:
139
- email_data = []
140
- for doc in emails:
141
- d = doc.to_dict()
142
- email_data.append({
143
- "Email": d.get("email"),
144
- "Date": d.get("timestamp"),
145
- "Source": d.get("source", "unknown")
146
- })
147
-
148
- df_emails = pd.DataFrame(email_data)
149
- st.dataframe(df_emails, use_container_width=True)
150
-
151
- # Export Button
152
- csv = df_emails.to_csv(index=False).encode('utf-8')
153
- st.download_button(
154
- "πŸ“₯ Download Email List (CSV)",
155
- csv,
156
- "vivara_emails.csv",
157
- "text/csv",
158
- key='download-csv'
159
- )
160
- else:
161
- st.info("No subscribers yet.")
162
-
163
- # ==========================================
164
- # TAB 3: SOLIDITY FORGE (CONTRACTS)
165
- # ==========================================
166
- with tab3:
167
- col_a, col_b = st.columns([1.5, 1])
168
-
169
- with col_a:
170
  st.subheader("πŸ“ Contract Editor")
171
  default_code = """// SPDX-License-Identifier: MIT
172
  pragma solidity ^0.8.20;
173
  import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
174
 
175
- contract Vivara is ERC20 {
176
- constructor() ERC20("Vivara", "VIVR") {
177
- _mint(msg.sender, 1000000000 * 10**18);
178
  }
179
  }
180
  """
181
  code_input = st.text_area("Solidity Code", value=default_code, height=500)
182
 
183
- with col_b:
184
- st.subheader("πŸš€ Actions")
185
-
186
  if st.button("COMPILE"):
187
- with st.spinner("Compiling..."):
188
  try:
189
  install_solc('0.8.20')
190
- compiled_sol = compile_source(code_input, output_values=['abi', 'bin'], solc_version='0.8.20')
191
- contract_id, contract_interface = list(compiled_sol.items())[-1]
192
- st.session_state['abi'] = contract_interface['abi']
193
- st.session_state['bytecode'] = contract_interface['bin']
194
- st.success(f"Compiled: {contract_id}")
195
  except Exception as e:
196
  st.error(f"Error: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
 
198
- if st.button("DEPLOY TO POLYGON"):
199
- if 'bytecode' not in st.session_state:
200
- st.warning("Compile first!")
201
- elif not private_key:
202
- st.error("No Private Key!")
203
- else:
204
- try:
205
- w3 = Web3(Web3.HTTPProvider(rpc_url))
206
- acct = w3.eth.account.from_key(private_key)
207
-
208
- Contract = w3.eth.contract(abi=st.session_state['abi'], bytecode=st.session_state['bytecode'])
209
- construct_txn = Contract.constructor().build_transaction({
210
- 'from': acct.address,
211
- 'nonce': w3.eth.get_transaction_count(acct.address),
212
- 'gas': 3000000,
213
- 'gasPrice': w3.to_wei('50', 'gwei'),
214
- 'chainId': int(chain_id)
215
- })
 
 
 
 
 
 
 
216
 
217
- signed = w3.eth.account.sign_transaction(construct_txn, private_key)
218
- tx_hash = w3.eth.send_raw_transaction(signed.rawTransaction)
219
- st.success(f"πŸš€ Deployed! TX: {w3.to_hex(tx_hash)}")
220
- except Exception as e:
221
- st.error(f"Deploy Error: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  from firebase_admin import credentials, firestore
9
 
10
  # --- PAGE CONFIG ---
11
+ st.set_page_config(page_title="Vivara Forge", page_icon="🦁", layout="wide")
 
12
 
13
+ # --- SESSION STATE SETUP ---
14
+ if 'is_creator' not in st.session_state:
15
+ st.session_state['is_creator'] = False
16
+
17
+ # --- 1. FIREBASE CONNECTION (Backend) ---
18
+ # This allows the app to talk to your database
19
  if not firebase_admin._apps:
20
  key_json = os.getenv("FIREBASE_SERVICE_ACCOUNT")
21
  if key_json:
 
23
  cred_dict = json.loads(key_json)
24
  cred = credentials.Certificate(cred_dict)
25
  firebase_admin.initialize_app(cred)
 
26
  except Exception as e:
27
+ st.warning("⚠️ Firebase Key Error. Admin features disabled.")
28
  else:
29
+ st.warning("⚠️ Admin Database Not Connected (Add FIREBASE_SERVICE_ACCOUNT secret)")
30
 
31
  try:
32
  db = firestore.client()
33
  except:
34
  db = None
35
 
36
+ # --- SIDEBAR: LOGIN & WALLET ---
37
  with st.sidebar:
38
+ st.header("πŸ‘€ Identity")
39
+
40
+ # LOGIN FORM
41
+ if not st.session_state['is_creator']:
42
+ with st.expander("Creator Login"):
43
+ admin_pass = st.text_input("Admin Password", type="password")
44
+ if st.button("Unlock Creator Mode"):
45
+ # Check against the secret you saved in Hugging Face
46
+ if admin_pass == os.getenv("ADMIN_PASSWORD"):
47
+ st.session_state['is_creator'] = True
48
+ st.success("Welcome back, Fugth.")
49
+ st.rerun()
50
+ else:
51
+ st.error("Wrong Password")
52
+ else:
53
+ st.success("🟒 CREATOR MODE ACTIVE")
54
+ if st.button("Logout"):
55
+ st.session_state['is_creator'] = False
56
+ st.rerun()
57
+
58
+ st.divider()
59
+
60
+ st.header("βš™οΈ Network Settings")
61
  rpc_url = st.text_input("RPC URL", value="https://polygon-rpc.com")
62
  chain_id = st.number_input("Chain ID", value=137)
63
 
64
+ # Wallet Status
65
+ pk = os.getenv("PRIVATE_KEY")
66
+ if pk:
67
+ st.info("πŸ”‘ Admin Wallet Loaded")
68
  else:
69
+ st.warning("⚠️ No Wallet Key Found")
70
 
71
+ # --- MAIN APP LOGIC ---
 
72
 
73
+ # IF CREATOR: Show Everything (3 Tabs)
74
+ # IF PUBLIC: Show Only Forge (1 Tab)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
+ if st.session_state['is_creator']:
77
+ st.title("🦁 Vivara Command Center")
78
+ tabs = st.tabs(["βš’οΈ Solidity Forge", "πŸ‘₯ User Database", "πŸ’° Coin & Stats"])
79
+ else:
80
+ st.title("βš’οΈ Vivara Forge (Public)")
81
+ st.caption("Open Source Smart Contract Deployment Tool")
82
+ tabs = st.tabs(["βš’οΈ Solidity Forge"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
  # ==========================================
85
+ # TAB 1: SOLIDITY FORGE (PUBLIC)
86
  # ==========================================
87
+ with tabs[0]:
88
+ col1, col2 = st.columns([1.5, 1])
89
 
90
+ with col1:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  st.subheader("πŸ“ Contract Editor")
92
  default_code = """// SPDX-License-Identifier: MIT
93
  pragma solidity ^0.8.20;
94
  import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
95
 
96
+ contract MyToken is ERC20 {
97
+ constructor() ERC20("MyToken", "MTK") {
98
+ _mint(msg.sender, 1000 * 10**18);
99
  }
100
  }
101
  """
102
  code_input = st.text_area("Solidity Code", value=default_code, height=500)
103
 
104
+ with col2:
105
+ st.subheader("πŸš€ Compiler")
 
106
  if st.button("COMPILE"):
107
+ with st.spinner("Installing Compiler..."):
108
  try:
109
  install_solc('0.8.20')
110
+ compiled = compile_source(code_input, output_values=['abi', 'bin'], solc_version='0.8.20')
111
+ contract_id, iface = list(compiled.items())[-1]
112
+ st.session_state['abi'] = iface['abi']
113
+ st.session_state['bin'] = iface['bin']
114
+ st.success(f"βœ… Compiled: {contract_id}")
115
  except Exception as e:
116
  st.error(f"Error: {e}")
117
+
118
+ st.divider()
119
+
120
+ # DEPLOY BUTTON (Only enabled if Creator logged in OR use Metamask injection trick)
121
+ # Since this is Python-based, usually only the Admin deploys via the server key.
122
+ if st.session_state['is_creator']:
123
+ if st.button("DEPLOY (Admin Wallet)"):
124
+ if not pk:
125
+ st.error("No Private Key!")
126
+ else:
127
+ try:
128
+ w3 = Web3(Web3.HTTPProvider(rpc_url))
129
+ acct = w3.eth.account.from_key(pk)
130
+ Contract = w3.eth.contract(abi=st.session_state['abi'], bytecode=st.session_state['bin'])
131
+ tx = Contract.constructor().build_transaction({
132
+ 'from': acct.address,
133
+ 'nonce': w3.eth.get_transaction_count(acct.address),
134
+ 'gas': 3000000,
135
+ 'gasPrice': w3.to_wei('50', 'gwei'),
136
+ 'chainId': int(chain_id)
137
+ })
138
+ signed = w3.eth.account.sign_transaction(tx, pk)
139
+ tx_hash = w3.eth.send_raw_transaction(signed.rawTransaction)
140
+ st.success(f"πŸš€ Deployed! TX: {w3.to_hex(tx_hash)}")
141
+ except Exception as e:
142
+ st.error(f"Deploy Error: {e}")
143
+ else:
144
+ st.info("πŸ”’ Server-side deployment is restricted to Admins. Public deployment via MetaMask coming soon.")
145
 
146
+ # ==========================================
147
+ # TAB 2: USER DATABASE (CREATOR ONLY)
148
+ # ==========================================
149
+ if st.session_state['is_creator']:
150
+ with tabs[1]:
151
+ st.header("πŸ‘₯ User Management")
152
+ if db:
153
+ users_ref = db.collection("users")
154
+ all_users = list(users_ref.stream())
155
+
156
+ founders = 0
157
+ alphas = 0
158
+
159
+ data = []
160
+ for doc in all_users:
161
+ u = doc.to_dict()
162
+ inv = u.get("inventory", [])
163
+
164
+ tier = "Free"
165
+ if "FOUNDER" in inv:
166
+ tier = "πŸ† GOLD"
167
+ founders += 1
168
+ elif "ALPHA" in inv:
169
+ tier = "πŸ₯ˆ SILVER"
170
+ alphas += 1
171
 
172
+ data.append({
173
+ "Name": u.get("displayName", "Unknown"),
174
+ "Email": u.get("email", "-"),
175
+ "Tier": tier,
176
+ "Rank": u.get("redeem_rank", "-")
177
+ })
178
+
179
+ k1, k2, k3 = st.columns(3)
180
+ k1.metric("Total Users", len(all_users))
181
+ k2.metric("Founders", founders)
182
+ k3.metric("Revenue", f"${(founders + alphas) * 5}")
183
+
184
+ st.dataframe(pd.DataFrame(data), use_container_width=True)
185
+
186
+ # NEWSLETTER EXPORT
187
+ st.subheader("πŸ“§ Newsletter List")
188
+ news_docs = list(db.collection("newsletters").stream())
189
+ emails = [d.to_dict().get("email") for d in news_docs]
190
+ st.write(f"collected {len(emails)} emails")
191
+ st.download_button("Download CSV", pd.DataFrame(emails, columns=["Email"]).to_csv(), "emails.csv")
192
+
193
+ # ==========================================
194
+ # TAB 3: COIN & STATS (CREATOR ONLY)
195
+ # ==========================================
196
+ if st.session_state['is_creator']:
197
+ with tabs[2]:
198
+ st.header("πŸ’° Vivara Coin Stats")
199
+ # You can add coin burning logic here later
200
+ st.info("Connect Token Contract to see live burn stats.")