· 6 years ago · Apr 12, 2020, 11:30 PM
1
2import flask, random, threading, time, requests, json
3from datetime import timedelta, datetime
4
5from decimal import Decimal
6from decimal import getcontext
7from decimal import ROUND_DOWN
8getcontext().prec = 8
9getcontext().rounding = ROUND_DOWN
10
11import smtplib
12from email.mime.multipart import MIMEMultipart
13from email.mime.text import MIMEText
14from email.mime.base import MIMEBase
15from email import encoders
16def sendMail(toaddr, subject, body):
17 # constructct the email
18 msg = MIMEMultipart()
19 msg['From'] = config["automation email"]
20 msg['To'] = toaddr
21 msg['Subject'] = subject
22 msg.attach(MIMEText(body, 'plain'))
23 text = msg.as_string()
24
25 # login to gmail and send the email
26 try:
27 server = smtplib.SMTP('smtp.gmail.com', 587)
28 server.starttls()
29 server.login(config["automation email"], config["automation email password"])
30 server.sendmail(config["automation email"], toaddr, text)
31 server.quit()
32 return True
33 except:
34 server.quit()
35 print("Email Failed To Send")
36 return False
37
38
39app = flask.Flask(__name__)
40
41with open("data/users.json", "r") as f:
42 users = json.loads("".join(f.readlines()))
43with open("data/data.json", "r") as f:
44 data = json.loads("".join(f.readlines()))
45with open("data/config.json", "r") as f:
46 config = json.loads("".join(f.readlines()))
47with open("data/binance_coins.json", "r") as f:
48 binance_coins = json.loads("".join(f.readlines()))
49
50def save_worker():
51 print("saving...")
52 with open("data/users.json", "w") as f:
53 f.write(json.dumps(users, indent=4))
54 with open("data/data.json", "w") as f:
55 f.write(json.dumps(data, indent=4))
56 print("data saved!")
57
58def save():
59 threading.Thread(target=save_worker).start()
60
61def time_string():
62 ts = time.time()
63 utc = datetime.utcfromtimestamp(ts)
64 return utc.strftime('%Y-%m-%d %H:%M:%S')
65
66sessions = {}
67def validate(r=None):
68 if r is None:
69 r = {}
70
71 if "ses" not in flask.request.cookies:
72 try:
73 ses = int(r["ses"])
74
75 if ses in sessions:
76 return sessions[ses]
77 else:
78 # That sessionID does not exist
79 return False
80 except:
81 pass
82
83 # the sessionID cookie is not set
84 return False
85
86 ses = int(flask.request.cookies["ses"])
87
88 if ses in sessions:
89 return sessions[ses]
90 else:
91 # That sessionID does not exist
92 return False
93
94log = []
95for i in range(100):
96 log.append("")
97
98def logRequest(username, request_data):
99 global log
100
101 if not username:
102 username = "<GUEST>"
103 s = username + ": " + json.dumps(request_data)
104 print(s)
105 log = [s] + log
106 del log[-1]
107
108def pay(username, dollars, reason):
109 price = int(Decimal(dollars) * 10000)
110 if users[username]["balance"] < price:
111 return False
112
113 users[username]["balance"] -= price
114 data["profit"] += price
115 users[username]["alerts"].append("[{}] Paid ${} for {}".format(time_string(), dollars, reason))
116 data["transactions"].append("[{}] [{}] paid ${} for {}".format(time_string(), username, dollars, reason))
117 return True
118
119@app.route("/<path:filename>", methods=["GET"])
120def file_reader(filename):
121 if filename in config["hidden files"]:
122 return flask.abort(403)
123
124 return flask.send_from_directory("", filename)
125
126@app.route("/data", methods=["GET"])
127def data_endpoint():
128 username = validate()
129 if username != config["admin username"]:
130 return "Sorry, you are not logged in as an admin."
131
132 s = json.dumps(data, indent=4)
133 s += "\n\n"
134 s += json.dumps(users, indent=4)
135 with open("data/data.txt", "w") as f:
136 f.write(s)
137 return flask.send_from_directory("data", "data.txt")
138
139@app.route("/stats", methods=["GET"])
140def stats_endpoint():
141 stats = """
142 <a href="/html/dashboard.html"> Back To Dashboard </a> <br> <br>
143 We have {} users <br>
144 We have paid ${} of interest <br>
145 We have made ${} of profit <br>
146 """.format(len(users), data["interest paid"] / 10000, (data["profit"] + data["interest earned"]) / 10000)
147 return stats
148
149@app.route("/", methods=["GET"])
150def home():
151 return flask.redirect("/html/welcome.html")
152
153@app.route("/logout", methods=["GET"])
154def logout():
155 ses = int(flask.request.cookies["ses"])
156 del sessions[ses]
157 return flask.redirect("/html/welcome.html")
158
159@app.route("/server", methods=["POST"])
160def request_endpoint():
161 request_data = json.loads(flask.request.data.decode("UTF-8"))
162 response = process_request(request_data)
163 if response is None:
164 raise ValueError("INVALID REQEUST")
165 return json.dumps(response)
166
167def process_request(r):
168 page = r["PATH"].split("/")[-1].split(".")[0]
169 action = r["action"]
170 username = validate(r)
171 logRequest(username, r)
172
173 if action == "ping":
174 return "You have reached the server!"
175
176 if action == "get basic current user data":
177 if not username:
178 return False
179 keys = ["name", "balance", "rank", "email", "pending balance"]
180 userdata = {"username": username}
181 for key in keys:
182 userdata[key] = users[username][key]
183 return userdata
184
185 if action == "get binance coins":
186 return binance_coins
187
188 if page == "login":
189 if action == "signup":
190 if r["username"] in users:
191 return {"success": False, "message": "Sorry, that username is already in use. Please login or try a different username."}
192
193 users[r["username"]] = {
194 "name": r["name"],
195 "email": r["email"],
196 "password": r["password"],
197 "balance": 0, # stored as hundredths of a cent
198 "alerts": ["[{}] Account Created".format(time_string())],
199 "rank": 0, # rank_names = ["basic", "premium", "platinum"]
200 "shares": 0,
201 "share price": 0,
202 "pending crypto orders": [],
203 "crypto": {}
204 }
205 action = "login"
206
207 if action == "login":
208 if r["username"] not in users:
209 return {"success": False, "message": "Sorry, that user does not have an account. Please register first."}
210 if r["password"] != users[r["username"]]["password"]:
211 return {"success": False, "message": "Sorry, incorrect Password. Please try again."}
212
213 ses = random.randrange(2**32)
214 sessions[ses] = r["username"]
215 return {"success": True, "ses": ses, "message": "Logged in as " + r["username"]}
216
217 if page == "dashboard":
218 if not username:
219 return {"success": False, "message": "You must be logged in to access this page"}
220
221 if action == "get alerts":
222 return {"success": True, "alerts": users[username]["alerts"]}
223
224 if action == "clear alerts":
225 users[username]["alerts"] = []
226 return {"success": True, "message": "Notifications cleared."}
227
228 if action == "transfer":
229 try:
230 amount = int(Decimal(r["amount"]) * 10000)
231 except:
232 return {"success": False, "message": "The transfer amount must be a number"}
233
234 if amount <= 0:
235 return {"success": False, "message": "Transfer amount must be greater than 0"}
236
237 if r["username"] not in users:
238 return {"success": False, "message": "That user does not exist"}
239
240 if users[username]["balance"] >= amount:
241 users[username]["balance"] -= amount
242 users[r["username"]]["balance"] += amount
243 users[username]["alerts"].append("[{}] Transfered ${} to {}".format(time_string(), amount/10000, r["username"]))
244 users[r["username"]]["alerts"].append("[{}] Recieved transfer of ${} from {}".format(time_string(), amount/10000, username))
245 data["transactions"].append("[{}] [{}] transfered ${} to {}".format(time_string(), username, amount/10000, r["username"]))
246
247 return {"success": True, "message": "Your transfer has been made"}
248 else:
249 return {"success": False, "message": "Your balance is to low to transfer that much"}
250
251 if page == "deposit":
252 if action == "crypto address":
253 return get_deposit_address(r["sym"])
254
255 if action == "scan crypto deposits":
256 amount = Decimal(r["amount"])
257 deposits = get_deposits()
258
259 for deposit in deposits:
260 if deposit["asset"] == r["sym"]:
261 if Decimal(str(deposit["amount"])) == amount or True:
262 if deposit["status"] == 0:
263 return {"success": False, "message": "Deposit Pending..."}
264 if deposit["status"] == 6:
265 return {"success": False, "message": "Deposit Pending. Please scan again once your transaction has 2 blockchain confirmations"}
266
267 if deposit["status"] == 1:
268 if [r["sym"], deposit["txId"]] in data["credited crypto transactions"]:
269 return {"success": False, "message": "Deposit Already Credited"}
270
271 data["credited crypto transactions"].append([r["sym"], deposit["txId"]])
272 net_amount = ( amount / Decimal("1.001") ).quantize(Decimal("0.123456"))
273 price = Decimal(get_crypto_price(r["sym"]))
274 sell_crypto(net_amount, r["sym"], price)
275
276 to_credit = int( price * net_amount * 10000 )
277 users[username]["balance"] += to_credit
278 users[username]["alerts"].append("[{}] Deposited ${} via {}".format(time_string(), to_credit/10000, r["sym"]))
279 data["transactions"].append("[{}] [{}] Deposited ${} via {}".format(time_string(), username, to_credit/10000, r["sym"]))
280
281
282 return {"success": True, "message": "Deposit Credited"}
283
284 return {"success": False, "message": "Deposit Not Found"}
285
286 if page == "withdraw":
287 if action == "crypto withdrawal data":
288 withdrawal_data = get_withdraw_data(r["sym"])
289 if not withdrawal_data:
290 return {"success": False, "message": "Unfortionatly, that coin is not supported. We applologise for the inconvinience"}
291 withdrawal_data["success"] = True
292 return withdrawal_data
293
294 if action == "withdraw":
295 try:
296 amount = int(Decimal(r["amount"]) * 10000)
297 except:
298 return {"success": False, "message": "The withdrawal amount must be a number"}
299
300 if r["method"] == "interac":
301 if amount < 10000:
302 return {"success": False, "message": "The minimum withdrawal amount is $1"}
303 method = "via interac e-transfer"
304 fee = 0
305
306 elif r["method"] == "crypto":
307 withdrawal_data = get_withdraw_data(r["sym"])
308 minimum = max( Decimal(withdrawal_data["min"]), 10 ) * 10000
309 if amount < minimum:
310 return {"success": False, "message": "The minimum withdrawal amount is $" + str(minimum/10000)}
311 fee = int(( amount + (Decimal(withdrawal_data["fee"])*10000) ) * Decimal("0.001")) # transaction fee to convert from USDT to thier crypto and miner fee to send it
312 method = "via {} with ${} fee".format(r["sym"], fee/10000)
313
314 if users[username]["balance"] >= (amount + fee):
315 users[username]["balance"] -= amount + fee
316 users[username]["alerts"].append("[{}] Submit withdrawal request for ${} ({})".format(time_string(), amount/10000, method))
317 data["transactions"].append("[{}] [{}] Submited a withdrawal request for ${} ({})".format(time_string(), username, amount/10000, method))
318
319 if r["method"] == "interac":
320 msg = """
321 Username: {} \n
322 Email: {} \n
323 Amount: ${}
324 """.format(username, r["address"], r["amount"])
325 sendMail(config["admin email"], "Interac Withdrawal Request", msg)
326
327 elif r["method"] == "crypto":
328 price = Decimal(get_crypto_price(r["sym"]))
329 crypto_amount = (amount / 10000) * price
330 amount_to_buy = crypto_amount + (fee / 10000 * price)
331 buy_crypto(amount_to_buy, r["sym"], price)
332 withdraw_crypto(crypto_amount, r["sym"], r["address"], r["tag"])
333
334 return {"success": True, "message": "Your withdrawal request has been submited"}
335 else:
336 return {"success": False, "message": "Your balance is to low to withdraw that much"}
337
338 if page == "crypto_trading":
339 if action == "get orders":
340 my_orders = []
341 for sym, txID, amount in users[username]["pending crypto orders"]:
342 if sym != r["sym"]:
343 continue
344
345 order_data = query_order(txID, sym)
346
347 if order_data["status"] == "FILLED":
348 if sym not in users[username]["crypto"]:
349 users[username]["crypto"][sym] = 0
350
351 if order_data["side"] == "BUY":
352 users[username]["crypto"][sym] = str( Decimal(users[username]["crypto"][sym]) + Decimal(order_data["executedQty"]) )
353 if order_data["side"] == "SELL":
354 users[username]["crypto"][sym] = str( Decimal(users[username]["crypto"][sym]) - Decimal(order_data["executedQty"]) )
355 value = int( Decimal(order_data["price"]) * Decimal(order_data["executedQty"]) * 10000 )
356 users[username]["balance"] += value
357 users[username]["alerts"].append("[{}] Sold {} {} for ${}".format(time_string(), order_data["executedQty"], sym, value/10000))
358 data["transactions"].append("[{}] [{}] Sold {} {} for ${}".format(time_string(), username, order_data["executedQty"], sym, value/10000))
359
360 continue
361
362 order_data["buyAmount"] = amount
363
364 my_orders.append(order_data)
365 return my_orders
366
367 if action == "cancel order":
368 side = cancel_crypto_order(r["sym"], r["txID"])
369 index = users[username]["pending crypto orders"].index([r["sym"], r["txID"], r["buyAmount"]])
370 amount = Decimal(users[username]["pending crypto orders"][index][2])
371 if side == "BUY":
372 users[username]["balance"] += amount
373 msg = "$" + str(amount/10000)
374 elif side == "SELL":
375 users[username]["crypto"][sym] = str( Decimal(users[username]["crypto"][sym]) + amount )
376 msg = str(amount)
377 users[username]["alerts"].append("[{}] Cancel {} order for {}".format(time_string(), r["sym"], msg))
378 data["transactions"].append("[{}] [{}] Cancel {} order for {}".format(time_string(), username, r["sym"], msg))
379
380 return {"success": True, "message": "Order canceled"}
381
382 if action == "buy":
383 price = Decimal(r["price"])
384 if price <= 0:
385 return {"success": False, "message": "Price must be more than $0"}
386 amount = int(Decimal(r["amount"]) * price * 10000)
387 if amount <= (10*10000):
388 return {"success": False, "message": "The minimum order value is $10"}
389
390 fee = int(amount * (Decimal(config["crypto buy fee"][users[username]["rank"]]) / 1000))
391 if users[username]["balance"] <= (amount + fee):
392 return {"success": False, "message": "Your balance is too low to make that trade"}
393
394 users[username]["balance"] -= amount + fee
395 profit = int(amount * (Decimal(config["crypto buy fee"][users[username]["rank"]] - 2) / 1000))
396 data["profit"] += profit
397 users[username]["alerts"].append("[{}] Ordered {} {} for ${}".format(time_string(), r["amount"], r["sym"], amount + fee))
398 data["transactions"].append("[{}] [{}] Ordered {} {} for ${}".format(time_string(), username, r["amount"], r["sym"], amount + fee))
399
400 txID = buy_crypto(Decimal(r["amount"]) * Decimal("1.001"), r["sym"], r["price"])
401 users[username]["pending crypto orders"].append([sym, txID, amount])
402
403 return {"success": True, "message": "Buy order placed"}
404
405 if action == "sell":
406 if Decimal(r["price"]) <= 0:
407 return {"success": False, "message": "Price must be more than $0"}
408 if Decimal(users[username]["crypto"][sym]) <= Decimal(r["amount"]):
409 return {"success": False, "message": "Your balance is too low to make that trade"}
410 value = Decimal(r["price"]) * Decimal(r["amount"])
411 if value <= 10:
412 return {"success": False, "message": "Minimum order value is $10"}
413
414 txID = sell_crypto(r["amount"], r["sym"], r["price"])
415 users[username]["crypto"][sym] = str( Decimal(users[username]["crypto"][sym]) - Decimal(r["amount"]) )
416 users[username]["pending crypto orders"].append([r["sym"], txID, r["amount"]])
417
418 return {"success": True, "message": "Sell order placed"}
419
420 if page == "stock":
421 if action == "get my share data":
422 return {"success": True, "shares": users[username]["shares"], "price": users[username]["share price"] / 10000}
423
424 if action == "change share price":
425 try:
426 price = int(Decimal(r["amount"]) * 10000)
427 except:
428 return {"success": False, "message": "The share price must be a number"}
429
430 if price <= 0:
431 return {"success": False, "message": "The share price must greater than 0"}
432
433 users[username]["share price"] = price
434 users[username]["alerts"].append("[{}] Share sell price changed to ${}".format(time_string(), r["amount"]))
435
436 return {"success": True, "message": "Share price changed to $" + r["amount"]}
437
438
439 if action == "get available shares":
440 info = []
441 for user in data["shareholders"]:
442 info.append({
443 "username": user,
444 "shares": users[user]["shares"],
445 "price": str(Decimal(users[user]["share price"]) / 10000 * Decimal("1.05"))
446 })
447
448 return {"success": True, "info": info}
449
450 if action == "buy":
451 seller = data["shareholders"][int(r["index"])]
452 number = int(r["number"])
453 price = users[seller]["share price"] * number
454 fee = price * Decimal("0.05")
455
456 if users[username]["balance"] >= (price + fee):
457 pay(username, fee/10000, "stock purchase fee")
458
459 if users[username]["shares"] == 0:
460 data["shareholders"].append(username)
461 users[username]["share price"] = int(users[seller]["share price"] * Decimal("1.1"))
462 users[username]["shares"] += number
463 users[seller]["shares"] -= number
464 if users[seller]["shares"] == 0:
465 del data["shareholders"][data["shareholders"].index(seller)]
466
467 users[username]["balance"] -= price
468 users[seller]["balance"] += price
469 users[username]["alerts"].append("[{}] Paid ${} for {} shares".format(time_string(), price/10000, number))
470 users[seller]["alerts"].append("[{}] Recieved ${} for {} shares".format(time_string(), price/10000, number))
471 data["transactions"].append("[{}] [{}] spent ${} to buy {} shares from {}".format(time_string(), username, price/10000, number, seller))
472
473 return {"success": True, "message": "You spent ${} to buy {} shares".format(Decimal(price/10000) + (fee/10000), number)}
474 else:
475 return {"success": False, "message": "Your balance is to low to buy that many shares"}
476
477 if page == "roll":
478 if action == "get house edge":
479 return {"success": False, "edge": data["house edge"][users[username]["rank"]]}
480
481 if action == "roll":
482 try:
483 amount = int(Decimal(r["bet"]) * 10000)
484 except:
485 return {"success": False, "message": "The bet amount must be a number"}
486
487 if amount < 1500:
488 return {"success": False, "message": "Minimum bet is $0.15"}
489
490 if users[username]["balance"] >= amount:
491 threshold = 50 - config["house edge"][users[username]["rank"]]
492 win = random.randrange(100) < threshold
493 if win:
494 users[username]["balance"] += amount
495 data["profit"] -= amount
496 users[username]["alerts"].append("[{}] Won roll bet for ${}".format(time_string(), r["bet"]))
497 data["transactions"].append("[{}] [{}] Won roll bet for ${}".format(time_string(), username, r["bet"]))
498
499 return {"success": True, "message": "You won your bet"}
500 else:
501 pay(username, r["bet"], "lost roll bet")
502 return {"success": True, "message": "You lost your bet"}
503 else:
504 return {"success": False, "message": "Your balance is to low to trabetnsfer that much"}
505
506 if page == "upgrade":
507 if action == "change plan":
508 new_rank = int(r["newRank"])
509 if new_rank <= users[username]["rank"]:
510 return {"rank": users[username]["rank"], "msg": "You have already purchased a higher plan than that and we do not offer refunds. Your rank has not been changed"}
511 else:
512 price = config["rank prices"][new_rank] - config["rank prices"][users[username]["rank"]]
513
514 success = pay(username, price, "an account upgrade")
515 if success:
516 users[username]["rank"] = new_rank
517 return {"rank": new_rank, "msg": "You have been charged ${} to upgrade your plan".format(price)}
518 else:
519 return {"rank": users[username]["rank"], "msg": "You cannot afford to change your plan"}
520
521 if page == "settings":
522 if action == "change email":
523 users[username]["alerts"].append("[{}] changed email from {} to {}".format(time_string(), users[username]["email"], r["email"]))
524 data["transactions"].append("[{}] [{}] changed email from {} to {}".format(time_string(), username, users[username]["email"], r["email"]))
525 users[username]["email"] = r["email"]
526 return {"success": True, "message": "Your email has been changed"}
527
528 if action == "change password":
529 users[username]["alerts"].append("[{}] changed password".format(time_string()))
530 users[username]["password"] = r["password"]
531 return {"success": True, "message": "Your password has been changed"}
532
533 if page == "contact":
534 msg = "Email: {} \nUsername: {} \nName: {}\n".format(r["email"], username, users[username]["name"])
535 msg += "Subject: {}\n".format(r["subject"])
536 msg += r["message"]
537
538 sendMail(config["admin email"], "Contact", msg)
539
540 return {"success": True}
541
542 if page == "contact-guest":
543 msg = "Email: {} \n".format(r["email"])
544 msg += "Subject: {}\n".format(r["subject"])
545 msg += r["message"]
546
547 sendMail(config["admin email"], "Guest Contact", msg)
548
549 return {"success": True}
550
551 if page == "admin":
552 if username != config["admin username"]:
553 return {"success": False, "message": "Sorry, you are not logged in as an admin."}
554
555 if action == "manual deposit":
556 try:
557 amount = int(Decimal(r["amount"]) * 10000)
558 except:
559 return {"success": False, "message": "The Deposit amount must be a number"}
560
561 if amount <= 0:
562 return {"success": False, "message": "Deposit amount must be greater than 0"}
563
564 if r["username"] not in users:
565 return {"success": False, "message": "That user does not exist"}
566
567 users[r["username"]]["balance"] += amount
568 users[r["username"]]["alerts"].append("[{}] Manual deposit of ${}".format(time_string(), amount/10000))
569 data["transactions"].append("[{}] Manual deposit of ${} to {}".format(time_string(), amount/10000, r["username"]))
570
571 return {"success": True, "message": "Your deposit has been made"}
572
573 if action == "dividend payment":
574 try:
575 amount = int(Decimal(r["amount"]) * 10000 / config["number of shares"])
576 except:
577 return {"success": False, "message": "The Deposit amount must be a number"}
578
579 # TODO: automaticly generate this dict
580 for username in data["shareholders"]:
581 shares = users[username]["shares"]
582 users[username]["balance"] += amount * shares
583 users[username]["alerts"].append("[{}] Dividend payment of ${}".format(time_string(), amount * shares/10000))
584 data["transactions"].append("[{}] Dividend payment of ${} to {}".format(time_string(), amount * shares/10000, username))
585
586 return {"success": True, "message": "Your payment has been distributed"}
587
588 if action == "record interest":
589 try:
590 amount = int(Decimal(r["amount"]) * 10000)
591 except:
592 return {"success": False, "message": "The interest amount must be a number"}
593
594 data["interest earned"] += amount
595
596 return {"success": True, "message": "Your interest payment has been recorded"}
597
598 # Personal
599 if True:
600 if username != config["admin username"]:
601 return {"success": False, "message": "not logged in as admin"}
602
603 if page == "binance":
604 if action == "get deposits":
605 return get_deposits()
606
607 if action == "get balance":
608 return get_binance_balance()
609
610 if action == "price":
611 return get_crypto_price(r["sym"])
612
613 if action == "crypto address":
614 return get_deposit_address(r["sym"])
615
616 if page == "expenses":
617 if action == "new payment":
618 data["personal"]["payments"].append({"name": r["name"], "store": r["store"], "price": r["price"], "date": r["date"]})
619 return "Expense added: {} from {}".format(r["name"], r["store"])
620
621 if action == "get payments":
622 return data["personal"]["payments"]
623
624 if action == "remove payment":
625 del data["personal"]["payments"][r["index"]]
626 return True
627
628 if action == "new store":
629 data["personal"]["stores"].append(r["name"])
630 return True
631
632 if action == "get stores":
633 return data["personal"]["stores"]
634
635 if action == "export":
636 return json.dumps({"stores": data["personal"]["stores"], "payments": data["personal"]["payments"]})
637
638
639# Hourly, Daily and Monthly
640if True:
641 # TODO change how to calculate now that it compunds monthly
642 def calc_daily_rate(apy):
643 apy = Decimal(apy)
644 x = (apy / 100) + 1
645 x = x ** (Decimal(1) / Decimal(365))
646 x = (x - 1) # * 100 # uncomment for percentage
647 return x
648
649 def daily():
650 # wait until midnight
651 now = datetime.now()
652 then = now + timedelta(days=1)
653 then = datetime(then.year, then.month, then.day)
654 seconds = (then - now).seconds
655 print("Day ends in " + str(seconds))
656 time.sleep(seconds)
657
658 while True:
659 # pay interest
660 rates = []
661 for rate in config["annual percentage yield"]:
662 rates.append(calc_daily_rate(rate))
663 for user, user_data in users.items():
664 daily_rate = rates[user_data["rank"]]
665 payment = int(user_data["balance"] * daily_rate)
666 user_data["pending balance"] += payment
667 data["interest paid"] += payment
668 user_data["alerts"].append("[{}] ${} added to pending balance".format(time_string(), str(payment / 10000)))
669
670 # Wait a day
671 time.sleep(24*60*60)
672
673 threading.Thread(target=daily).start()
674
675
676 def hourly():
677 # wait until next hour
678 now = datetime.now()
679 then = now + timedelta(hours=1)
680 then = datetime(then.year, then.month, then.day, then.hour)
681 seconds = (then - now).seconds
682 print("Hour ends in " + str(seconds))
683 time.sleep(seconds)
684
685 while True:
686
687 save()
688
689 # Wait an hour
690 time.sleep(60*60)
691
692 threading.Thread(target=hourly).start()
693
694
695 def monthly():
696 while True:
697 # wait until first of next month
698 # (have to calculate every time cause months are different lengths)
699 now = datetime.now()
700 then = datetime(now.year, (now.month + 1) % 12, 1)
701 seconds = (then - now).seconds
702 print("Month ends in " + str(seconds))
703 time.sleep(seconds)
704
705 # pay interest
706 for user, user_data in users.items():
707 user_data["balance"] += user_data["pending balance"]
708 user_data["alerts"].append("[{}] ${} Monthly Interest Payment".format(time_string(), str(user_data["pending balance"] / 10000)))
709 data["transactions"].append("[{}] [{}] ${} Monthly Interest Payment".format(time_string(), user, str(user_data["pending balance"] / 10000)))
710 user_data["pending balance"] = 0
711
712 threading.Thread(target=monthly).start()
713
714# Binance API
715if True:
716 api = "kGAKxjkOlmEfpcpGNXas9GOzxDXLGvJpervlTs3tQRGakX6mMHOkK2vl0VvatodH"
717 secret = "MVIwiflhkYlnJdjDLRKd5JBvBZKUsJ2NQqfXXElZ1S94XXF7VYwCeQJrRZHMnFpz"
718
719 import hmac
720 import hashlib
721 from urllib.parse import urlencode
722
723 def create_sha256_signature(key, message):
724 byte_key = key.encode()
725 message = message.encode()
726 return hmac.new(byte_key, message, hashlib.sha256).hexdigest().upper()
727
728 def get_withdraw_data(sym):
729 data = {
730 "timestamp": int(time.time() * 1000)
731 }
732 data = urlencode(data)
733 signature = create_sha256_signature(secret, data)
734 r = requests.get("https://api.binance.com/wapi/v3/assetDetail.html?{}&signature={}".format(data, signature), headers={'X-MBX-APIKEY': api})
735 response = r.json()
736
737 if sym != "USDT":
738 r = requests.get("https://api.binance.com/api/v1/ticker/price?symbol={}USDT".format(sym), headers={'X-MBX-APIKEY': api})
739 try:
740 price = r.json()["price"]
741 except:
742 print(r.json())
743 return False
744 else:
745 price = 1
746
747 data = response["assetDetail"][sym]
748 return {"min": str(Decimal(data["minWithdrawAmount"]) * Decimal(price)), "fee": str((Decimal(data["withdrawFee"]) * Decimal(price)).quantize(Decimal("0.1234")))}
749
750 def buy_crypto(amount, sym, price):
751 amount = amount.quantize(Decimal("0.123456")) # Round to 6 decimal places
752 price = price.quantize(Decimal("0.1234")) # Round to 6 decimal places
753 data = {"symbol": sym + "USDT",
754 "side": "BUY",
755 "type": "LIMIT",
756 "timeInForce": "GTC",
757 "quantity": amount,
758 "price": price,
759 "timestamp": int(time.time() * 1000)}
760 data = urlencode(data)
761 signature = create_sha256_signature(secret, data)
762
763 r = requests.post("https://api.binance.com/api/v3/order?{}&signature={}".format(data, signature), headers={'X-MBX-APIKEY': api})
764 response = r.json()
765 try:
766 ID = response["orderId"]
767 data["binance transactions"].append("[{}] Limit order: Buy {} {} at ${}".format(time_string(), amount, sym, price))
768 return ID
769 except:
770 print(response)
771 return False
772
773 def withdraw_crypto(amount, sym, address, tag):
774 data = {
775 "asset": sym,
776 "address": address,
777 "addressTag": tag,
778 "amount": amount,
779 "timestamp": int(time.time() * 1000)}
780 data = urlencode(data)
781 signature = create_sha256_signature(secret, data)
782
783 r = requests.post("https://api.binance.com/api/v3/withdraw?{}&signature={}".format(data, signature), headers={'X-MBX-APIKEY': api})
784 response = r.json()
785 data["binance transactions"].append("[{}] Withdraw {} {} to {} ({})".format(time_string(), amount, sym, address, tag))
786 return response
787
788 def get_deposits():
789 data = {
790 "timestamp": int(time.time() * 1000)
791 }
792 data = urlencode(data)
793 signature = create_sha256_signature(secret, data)
794 r = requests.get("https://api.binance.com/wapi/v3/depositHistory.html?{}&signature={}".format(data, signature), headers={'X-MBX-APIKEY': api})
795 response = json.loads(r.text)
796 deposits = response["depositList"]
797 return deposits
798
799 def get_deposit_address(sym):
800 data = {
801 "timestamp": int(time.time() * 1000),
802 "asset": sym
803 }
804 data = urlencode(data)
805 signature = create_sha256_signature(secret, data)
806 r = requests.get("https://api.binance.com/wapi/v3/depositAddress.html?{}&signature={}".format(data, signature), headers={'X-MBX-APIKEY': api})
807 response = r.json()
808 return response
809
810 def sell_crypto(amount, sym, price):
811 amount = amount.quantize(Decimal("0.123456")) # Round to 6 decimal places
812 data = {"symbol": sym + "USDT",
813 "side": "SELL",
814 "type": "LIMIT",
815 "timeInForce": "GTC",
816 "quantity": amount,
817 "price": price,
818 "timestamp": int(time.time() * 1000)}
819 data = urlencode(data)
820 signature = create_sha256_signature(secret, data)
821
822 r = requests.post("https://api.binance.com/api/v3/order?{}&signature={}".format(data, signature), headers={'X-MBX-APIKEY': api})
823 response = r.json()
824 try:
825 ID = response["orderId"]
826 data["binance transactions"].append("[{}] Limit order: Sell {} {} at ${}".format(time_string(), amount, sym, price))
827 return ID
828 except:
829 print(response)
830 return False
831
832 def get_crypto_price(sym):
833 r = requests.get("https://api.binance.com/api/v1/ticker/price?symbol={}USDT".format(sym), headers={'X-MBX-APIKEY': api})
834 try:
835 price = r.json()["price"]
836 return price
837 except:
838 print(r.json())
839 return False
840
841 def query_order(txID, sym):
842 data = {"symbol": sym + "USDT",
843 "orderId": txID,
844 "timestamp": int(time.time() * 1000)}
845 data = urlencode(data)
846 signature = create_sha256_signature(secret, data)
847
848 r = requests.post("https://api.binance.com/api/v3/order?{}&signature={}".format(data, signature), headers={'X-MBX-APIKEY': api})
849 response = r.json()
850 return response
851
852 def cancel_crypto_order(sym, txID):
853 amount = amount.quantize(Decimal("0.123456")) # Round to 6 decimal places
854 data = {"symbol": sym + "USDT",
855 "orderId": txID,
856 "timestamp": int(time.time() * 1000)}
857 data = urlencode(data)
858 signature = create_sha256_signature(secret, data)
859
860 r = requests.delete("https://api.binance.com/api/v3/order?{}&signature={}".format(data, signature), headers={'X-MBX-APIKEY': api})
861 return r.json()["side"]
862
863 def get_binance_balance():
864 data = {
865 "timestamp": int(time.time() * 1000)
866 }
867 data = urlencode(data)
868 signature = create_sha256_signature(secret, data)
869 r = requests.get("https://api.binance.com/api/v3/account?{}&signature={}".format(data, signature), headers={'X-MBX-APIKEY': api})
870 response = json.loads(r.text)
871 deposits = response["balances"]
872 return deposits
873
874# Knock Knock Jokes
875if True:
876 def sendSchoolMail(toaddr, subject, body):
877 # constructct the email
878 msg = MIMEMultipart()
879 msg['From'] = "lukegl@elementhighschool.com"
880 msg['To'] = toaddr
881 msg['Subject'] = subject
882 msg.attach(MIMEText(body, 'plain'))
883 text = msg.as_string()
884
885 # login to gmail and send the email
886 try:
887 server = smtplib.SMTP('smtp.gmail.com', 587)
888 server.starttls()
889 server.login("lukegl@elementhighschool.com", "Febuary21")
890 server.sendmail("lukegl@elementhighschool.com", toaddr, text)
891 server.quit()
892 return True
893 except:
894 server.quit()
895 print("Email Failed To Send")
896 return False
897
898 with open("knock/knock.json", "r") as f:
899 jokes = json.loads("".join(f.readlines()))
900 with open("knock/email.json", "r") as f:
901 knock = json.loads("".join(f.readlines()))
902
903 def process_knock(r):
904 page = r["PATH"].split("/")[-1].split(".")[0]
905 action = r["action"]
906
907 if action == "get imgs":
908 return {
909 "stars": ["leo", "milkyway", "pat", "star", "starburst", "starclipart", "starfish", "throw"],
910 "notStars": ["chrome", "element", "fil", "tree"]
911 }
912
913 if action == "get joke":
914 return jokes[knock["joke i"]]
915
916 if action == "add email":
917 if r["email"] in knock["emails"]:
918 return "This email is already subscribed"
919 if r["email"] in knock["unsubed"]:
920 return "This email has been unsubscribed and cannot be readded"
921
922 knock["emails"].append(r["email"])
923 return "Email Added"
924
925 if action == "submit":
926 r = r["r"]
927 print(r)
928 action = r["action"]
929
930 if action == "unsub":
931 knock["to unsub"].append(knock["emails"][int(r["i"])])
932 return knock["emails"][int(r["i"])] + " has been unsubscribed"
933
934 @app.route("/knock_data", methods=["GET"])
935 def show_knock_data():
936 s = json.dumps(knock, indent=4)
937 with open("data/data.txt", "w") as f:
938 f.write(s)
939 return flask.send_from_directory("data", "data.txt")
940
941 @app.route("/knock", methods=["POST"])
942 def knock_request_endpoint():
943 request_data = json.loads(flask.request.data.decode("UTF-8"))
944 response = process_knock(request_data)
945 if response is None:
946 raise ValueError("INVALID REQEUST")
947 return json.dumps(response)
948
949 def dailyKnock():
950 # wait until 8
951 now = datetime.now()
952 then = now + timedelta(days=1)
953 then = datetime(then.year, then.month, then.day, 8)
954 seconds = (then - now).seconds
955 print("8:00 is in " + str(seconds))
956 time.sleep(seconds)
957
958 while True:
959 # process unsubscriptions
960 for email in knock["to unsub"]:
961 email_index = knock["emails"].index(email)
962 del knock["emails"][email_index]
963 knock["unsubed"].append(email)
964
965 # Increment Joke
966 knock["joke i"] += 1
967 knock["joke i"] = knock["joke i"] % len(jokes)
968
969 # Save
970 with open("knock/email.json", "w") as f:
971 f.write(json.dumps(knock, indent=4))
972
973 # send emails
974 for i in range(len(knock["emails"])):
975 msg = """
976 Knock Knock
977 Who's There: http://theelementhighschool.com/knock/joke.html?i={0}
978 Unsubscribe: http://theelementhighschool.com/knock/captcha.html?action=unsub&i={0}
979 More Info: http://theelementhighschool.com/knock/info.html
980 """.format(i)
981 sendSchoolMail(knock["emails"][i], "Knock Knock", msg)
982
983 # Wait a day
984 time.sleep(24*60*60)
985
986 threading.Thread(target=dailyKnock).start()
987
988
989### SOLUTIONS ###
990
991# Payment Proccessing
992if True:
993 pass
994
995
996
997app.run(host="0.0.0.0", port="80", threaded=True)
998
999server.py
1000Displaying server.py.