feat: Finish domain transfers
This commit is contained in:
parent
923b49b3ec
commit
8540265173
194
account.py
194
account.py
@ -1,3 +1,4 @@
|
||||
from datetime import datetime, timedelta
|
||||
from handywrapper import api
|
||||
import os
|
||||
import dotenv
|
||||
@ -34,6 +35,20 @@ def check_account(cookie: str):
|
||||
|
||||
return account
|
||||
|
||||
def check_password(cookie: str, password: str):
|
||||
account = check_account(cookie)
|
||||
if account == False:
|
||||
return False
|
||||
|
||||
# Check if the password is valid
|
||||
info = hsw.rpc_selectWallet(account)
|
||||
if info['error'] is not None:
|
||||
return False
|
||||
info = hsw.rpc_walletPassphrase(password,10)
|
||||
if info['error'] is not None:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def getBalance(account: str):
|
||||
# Get the total balance
|
||||
@ -54,6 +69,13 @@ def getBalance(account: str):
|
||||
|
||||
return {'available': available, 'total': total}
|
||||
|
||||
def getBlockHeight():
|
||||
# Get the block height
|
||||
info = hsd.getInfo()
|
||||
if 'error' in info:
|
||||
return 0
|
||||
return info['chain']['height']
|
||||
|
||||
def getAddress(account: str):
|
||||
# Get the address
|
||||
info = hsw.getAccountInfo(account, 'default')
|
||||
@ -149,7 +171,9 @@ def send(account,address,amount):
|
||||
response = hsw.rpc_selectWallet(account_name)
|
||||
if response['error'] is not None:
|
||||
return {
|
||||
"error": response['error']['message']
|
||||
"error": {
|
||||
"message": response['error']['message']
|
||||
}
|
||||
}
|
||||
|
||||
response = hsw.rpc_walletPassphrase(password,10)
|
||||
@ -158,13 +182,17 @@ def send(account,address,amount):
|
||||
# json={"passphrase": password,"timeout": 10})
|
||||
if response['error'] is not None:
|
||||
return {
|
||||
"error": response['error']['message']
|
||||
"error": {
|
||||
"message": response['error']['message']
|
||||
}
|
||||
}
|
||||
|
||||
response = hsw.rpc_sendToAddress(address,amount)
|
||||
if response['error'] is not None:
|
||||
return {
|
||||
"error": response['error']['message']
|
||||
"error": {
|
||||
"message": response['error']['message']
|
||||
}
|
||||
}
|
||||
return {
|
||||
"tx": response['result']
|
||||
@ -175,7 +203,9 @@ def getDomain(domain: str):
|
||||
response = hsd.rpc_getNameInfo(domain)
|
||||
if response['error'] is not None:
|
||||
return {
|
||||
"error": response['error']['message']
|
||||
"error": {
|
||||
"message": response['error']['message']
|
||||
}
|
||||
}
|
||||
return response['result']
|
||||
|
||||
@ -185,7 +215,9 @@ def renewDomain(account,domain):
|
||||
|
||||
if account_name == False:
|
||||
return {
|
||||
"error": "Invalid account"
|
||||
"error": {
|
||||
"message": "Invalid account"
|
||||
}
|
||||
}
|
||||
|
||||
response = hsw.sendRENEW(account_name,password,domain)
|
||||
@ -207,7 +239,9 @@ def setDNS(account,domain,records):
|
||||
|
||||
if account_name == False:
|
||||
return {
|
||||
"error": "Invalid account"
|
||||
"error": {
|
||||
"message": "Invalid account"
|
||||
}
|
||||
}
|
||||
|
||||
records = json.loads(records)
|
||||
@ -270,7 +304,9 @@ def revealAuction(account,domain):
|
||||
|
||||
if account_name == False:
|
||||
return {
|
||||
"error": "Invalid account"
|
||||
"error": {
|
||||
"message": "Invalid account"
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
@ -304,7 +340,9 @@ def bid(account,domain,bid,blind):
|
||||
|
||||
if account_name == False:
|
||||
return {
|
||||
"error": "Invalid account"
|
||||
"error": {
|
||||
"message": "Invalid account"
|
||||
}
|
||||
}
|
||||
|
||||
bid = int(bid)*1000000
|
||||
@ -315,7 +353,9 @@ def bid(account,domain,bid,blind):
|
||||
return response
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": str(e)
|
||||
"error": {
|
||||
"message": str(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -325,7 +365,9 @@ def openAuction(account,domain):
|
||||
|
||||
if account_name == False:
|
||||
return {
|
||||
"error": "Invalid account"
|
||||
"error": {
|
||||
"message": "Invalid account"
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
@ -333,5 +375,133 @@ def openAuction(account,domain):
|
||||
return response
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": str(e)
|
||||
}
|
||||
"error": {
|
||||
"message": str(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
def transfer(account,domain,address):
|
||||
account_name = check_account(account)
|
||||
password = ":".join(account.split(":")[1:])
|
||||
|
||||
if account_name == False:
|
||||
return {
|
||||
"error": {
|
||||
"message": "Invalid account"
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
response = hsw.sendTRANSFER(account_name,password,domain,address)
|
||||
return response
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": {
|
||||
"message": str(e)
|
||||
}
|
||||
}
|
||||
|
||||
def finalize(account,domain):
|
||||
account_name = check_account(account)
|
||||
password = ":".join(account.split(":")[1:])
|
||||
|
||||
if account_name == False:
|
||||
return {
|
||||
"error": {
|
||||
"message": "Invalid account"
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
response = hsw.sendFINALIZE(account_name,password,domain)
|
||||
return response
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": {
|
||||
"message": str(e)
|
||||
}
|
||||
}
|
||||
|
||||
def cancelTransfer(account,domain):
|
||||
account_name = check_account(account)
|
||||
password = ":".join(account.split(":")[1:])
|
||||
|
||||
if account_name == False:
|
||||
return {
|
||||
"error": {
|
||||
"message": "Invalid account"
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
response = hsw.rpc_selectWallet(account_name)
|
||||
if response['error'] is not None:
|
||||
return {
|
||||
"error": {
|
||||
"message": response['error']['message']
|
||||
}
|
||||
}
|
||||
response = hsw.rpc_walletPassphrase(password,10)
|
||||
if response['error'] is not None:
|
||||
return {
|
||||
"error": {
|
||||
"message": response['error']['message']
|
||||
}
|
||||
}
|
||||
response = hsw.rpc_sendCANCEL(domain)
|
||||
return response
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": {
|
||||
"message": str(e)
|
||||
}
|
||||
}
|
||||
|
||||
def revoke(account,domain):
|
||||
account_name = check_account(account)
|
||||
password = ":".join(account.split(":")[1:])
|
||||
|
||||
if account_name == False:
|
||||
return {
|
||||
"error": {
|
||||
"message": "Invalid account"
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
response = hsw.sendREVOKE(account_name,password,domain)
|
||||
return response
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": {
|
||||
"message": str(e)
|
||||
}
|
||||
}
|
||||
|
||||
def generateReport(account):
|
||||
domains = getDomains(account)
|
||||
format = str('{name},{expiry},{value},{maxBid}')
|
||||
|
||||
lines = [format.replace("{","").replace("}","")]
|
||||
for domain in domains:
|
||||
line = format.replace("{name}",domain['name'])
|
||||
expiry = "N/A"
|
||||
expiryBlock = "N/A"
|
||||
if 'daysUntilExpire' in domain['stats']:
|
||||
days = domain['stats']['daysUntilExpire']
|
||||
# Convert to dateTime
|
||||
expiry = datetime.now() + timedelta(days=days)
|
||||
expiry = expiry.strftime("%d/%m/%Y %H:%M:%S")
|
||||
expiryBlock = str(domain['stats']['renewalPeriodEnd'])
|
||||
|
||||
line = line.replace("{expiry}",expiry)
|
||||
line = line.replace("{state}",domain['state'])
|
||||
line = line.replace("{expiryBlock}",expiryBlock)
|
||||
line = line.replace("{value}",str(domain['value']/1000000))
|
||||
line = line.replace("{maxBid}",str(domain['highest']/1000000))
|
||||
line = line.replace("{openHeight}",str(domain['height']))
|
||||
lines.append(line)
|
||||
|
||||
return lines
|
184
main.py
184
main.py
@ -1,4 +1,5 @@
|
||||
import json
|
||||
import random
|
||||
from flask import Flask, make_response, redirect, request, jsonify, render_template, send_from_directory,send_file
|
||||
import os
|
||||
import dotenv
|
||||
@ -18,6 +19,7 @@ qrcode = QRcode(app)
|
||||
|
||||
# Change this if network fees change
|
||||
fees = 0.02
|
||||
revokeCheck = random.randint(100000,999999)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
@ -346,11 +348,124 @@ def manage(domain: str):
|
||||
raw_dns = str(dns).replace("'",'"')
|
||||
dns = render.dns(dns)
|
||||
|
||||
errorMessage = request.args.get("error")
|
||||
if errorMessage == None:
|
||||
errorMessage = ""
|
||||
address = request.args.get("address")
|
||||
if address == None:
|
||||
address = ""
|
||||
|
||||
finalize_time = ""
|
||||
# Check if the domain is in transfer
|
||||
if domain_info['info']['transfer'] != 0:
|
||||
current_block = account_module.getBlockHeight()
|
||||
finalize_valid = domain_info['info']['transfer']+288
|
||||
finalize_blocks = finalize_valid - current_block
|
||||
if finalize_blocks > 0:
|
||||
finalize_time = "in "+ str(finalize_blocks) + " blocks (~" + str(round(finalize_blocks/6)) + " hours)"
|
||||
else:
|
||||
finalize_time = "now"
|
||||
|
||||
return render_template("manage.html", account=account, sync=account_module.getNodeSync(),
|
||||
domain=domain,expiry=expiry, dns=dns,raw_dns=urllib.parse.quote(raw_dns))
|
||||
error=errorMessage, address=address,
|
||||
domain=domain,expiry=expiry, dns=dns,
|
||||
raw_dns=urllib.parse.quote(raw_dns),
|
||||
finalize_time=finalize_time)
|
||||
|
||||
|
||||
@app.route('/manage/<domain>/finalize')
|
||||
def finalize(domain: str):
|
||||
# Check if the user is logged in
|
||||
if request.cookies.get("account") is None:
|
||||
return redirect("/login")
|
||||
|
||||
|
||||
if not account_module.check_account(request.cookies.get("account")):
|
||||
return redirect("/logout")
|
||||
|
||||
domain = domain.lower()
|
||||
print(domain)
|
||||
response = account_module.finalize(request.cookies.get("account"),domain)
|
||||
if 'error' in response:
|
||||
print(response)
|
||||
return redirect("/manage/" + domain + "?error=" + response['error']['message'])
|
||||
|
||||
return redirect("/success?tx=" + response['hash'])
|
||||
|
||||
@app.route('/manage/<domain>/cancel')
|
||||
def cancelTransfer(domain: str):
|
||||
# Check if the user is logged in
|
||||
if request.cookies.get("account") is None:
|
||||
return redirect("/login")
|
||||
|
||||
|
||||
if not account_module.check_account(request.cookies.get("account")):
|
||||
return redirect("/logout")
|
||||
|
||||
domain = domain.lower()
|
||||
print(domain)
|
||||
response = account_module.cancelTransfer(request.cookies.get("account"),domain)
|
||||
if 'error' in response:
|
||||
if response['error'] != None:
|
||||
print(response)
|
||||
return redirect("/manage/" + domain + "?error=" + response['error']['message'])
|
||||
|
||||
return redirect("/success?tx=" + response['result']['hash'])
|
||||
|
||||
@app.route('/manage/<domain>/revoke')
|
||||
def revokeInit(domain: str):
|
||||
# Check if the user is logged in
|
||||
if request.cookies.get("account") is None:
|
||||
return redirect("/login")
|
||||
|
||||
|
||||
if not account_module.check_account(request.cookies.get("account")):
|
||||
return redirect("/logout")
|
||||
|
||||
domain = domain.lower()
|
||||
|
||||
content = f"Are you sure you want to revoke {domain}/?<br>"
|
||||
content += f"This will return the domain to the auction pool and you will lose any funds spent on the domain.<br>"
|
||||
content += f"This cannot be undone after the transaction is sent.<br><br>"
|
||||
content += f"Please enter your password to confirm."
|
||||
|
||||
cancel = f"/manage/{domain}"
|
||||
confirm = f"/manage/{domain}/revoke/confirm"
|
||||
action = f"Revoke {domain}/"
|
||||
|
||||
|
||||
return render_template("confirm-password.html", account=account_module.check_account(request.cookies.get("account")),
|
||||
sync=account_module.getNodeSync(),action=action,
|
||||
content=content,cancel=cancel,confirm=confirm,check=revokeCheck)
|
||||
|
||||
@app.route('/manage/<domain>/revoke/confirm', methods=["POST"])
|
||||
def revokeConfirm(domain: str):
|
||||
# Check if the user is logged in
|
||||
if request.cookies.get("account") is None:
|
||||
return redirect("/login")
|
||||
|
||||
|
||||
if not account_module.check_account(request.cookies.get("account")):
|
||||
return redirect("/logout")
|
||||
|
||||
domain = domain.lower()
|
||||
password = request.form.get("password")
|
||||
check = request.form.get("check")
|
||||
if check != str(revokeCheck):
|
||||
return redirect("/manage/" + domain + "?error=An error occurred. Please try again.")
|
||||
|
||||
response = account_module.check_password(request.cookies.get("account"),password)
|
||||
if response == False:
|
||||
return redirect("/manage/" + domain + "?error=Invalid password")
|
||||
|
||||
|
||||
response = account_module.revoke(request.cookies.get("account"),domain)
|
||||
if 'error' in response:
|
||||
print(response)
|
||||
return redirect("/manage/" + domain + "?error=" + response['error']['message'])
|
||||
|
||||
return redirect("/success?tx=" + response['hash'])
|
||||
|
||||
@app.route('/manage/<domain>/renew')
|
||||
def renew(domain: str):
|
||||
# Check if the user is logged in
|
||||
@ -365,7 +480,6 @@ def renew(domain: str):
|
||||
response = account_module.renewDomain(request.cookies.get("account"),domain)
|
||||
return redirect("/success?tx=" + response['hash'])
|
||||
|
||||
|
||||
@app.route('/manage/<domain>/edit')
|
||||
def editPage(domain: str):
|
||||
# Check if the user is logged in
|
||||
@ -451,6 +565,61 @@ def editSave(domain: str):
|
||||
return redirect("/manage/" + domain + "/edit?dns="+raw_dns+"&error=" + str(response['error']))
|
||||
return redirect("/success?tx=" + response['hash'])
|
||||
|
||||
@app.route('/manage/<domain>/transfer')
|
||||
def transfer(domain):
|
||||
if request.cookies.get("account") is None:
|
||||
return redirect("/login")
|
||||
|
||||
account = account_module.check_account(request.cookies.get("account"))
|
||||
if not account:
|
||||
return redirect("/logout")
|
||||
|
||||
# Get the address and amount
|
||||
address = request.args.get("address")
|
||||
|
||||
if address is None:
|
||||
return redirect("/manage/" + domain + "?error=Invalid address")
|
||||
|
||||
address_check = account_module.check_address(address,True,True)
|
||||
if not address_check:
|
||||
return redirect("/send?message=Invalid address&address=" + address)
|
||||
|
||||
address = address_check
|
||||
|
||||
toAddress = address
|
||||
if request.form.get('address') != address:
|
||||
toAddress = request.args.get('address') + "<br>" + address
|
||||
|
||||
action = f"Send {domain}/ to {request.form.get('address')}"
|
||||
content = f"Are you sure you want to send {domain}/ to {toAddress}<br><br>"
|
||||
content += f"This requires sending a finalize transaction 2 days after the transfer is initiated."
|
||||
|
||||
cancel = f"/manage/{domain}?address={address}"
|
||||
confirm = f"/manage/{domain}/transfer/confirm?address={address}"
|
||||
|
||||
|
||||
return render_template("confirm.html", account=account_module.check_account(request.cookies.get("account")),
|
||||
sync=account_module.getNodeSync(),action=action,
|
||||
content=content,cancel=cancel,confirm=confirm)
|
||||
|
||||
@app.route('/manage/<domain>/transfer/confirm')
|
||||
def transferConfirm(domain):
|
||||
if request.cookies.get("account") is None:
|
||||
return redirect("/login")
|
||||
|
||||
account = account_module.check_account(request.cookies.get("account"))
|
||||
if not account:
|
||||
return redirect("/logout")
|
||||
|
||||
# Get the address and amount
|
||||
address = request.args.get("address")
|
||||
response = account_module.transfer(request.cookies.get("account"),domain,address)
|
||||
if 'error' in response:
|
||||
return redirect("/manage/" + domain + "?error=" + response['error'])
|
||||
|
||||
return redirect("/success?tx=" + response['hash'])
|
||||
|
||||
|
||||
@app.route('/auction/<domain>')
|
||||
def auction(domain):
|
||||
# Check if the user is logged in
|
||||
@ -682,6 +851,17 @@ def logout():
|
||||
response.set_cookie("account", "", expires=0)
|
||||
return response
|
||||
|
||||
|
||||
@app.route('/report')
|
||||
def report():
|
||||
# Check if the user is logged in
|
||||
if request.cookies.get("account") is None:
|
||||
return redirect("/login")
|
||||
|
||||
account = account_module.check_account(request.cookies.get("account"))
|
||||
|
||||
return jsonify(account_module.generateReport(account))
|
||||
|
||||
#endregion
|
||||
|
||||
#region Assets and default pages
|
||||
|
85
templates/confirm-password.html
Normal file
85
templates/confirm-password.html
Normal file
@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html>
|
||||
<html data-bs-theme="dark" lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||
<title>Confirm - FireWallet</title>
|
||||
<link rel="icon" type="image/png" sizes="900x768" href="/assets/img/favicon.png">
|
||||
<link rel="icon" type="image/png" sizes="900x768" href="/assets/img/favicon.png">
|
||||
<link rel="icon" type="image/png" sizes="900x768" href="/assets/img/favicon.png">
|
||||
<link rel="icon" type="image/png" sizes="900x768" href="/assets/img/favicon.png">
|
||||
<link rel="icon" type="image/png" sizes="900x768" href="/assets/img/favicon.png">
|
||||
<link rel="stylesheet" href="/assets/bootstrap/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i&display=swap">
|
||||
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
|
||||
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
|
||||
<link rel="stylesheet" href="/assets/css/styles.min.css">
|
||||
</head>
|
||||
|
||||
<body id="page-top">
|
||||
<div id="wrapper">
|
||||
<nav class="navbar align-items-start sidebar sidebar-dark accordion bg-gradient-primary p-0 navbar-dark" style="background: var(--bs-primary-border-subtle);">
|
||||
<div class="container-fluid d-flex flex-column p-0"><a class="navbar-brand d-flex justify-content-center align-items-center sidebar-brand m-0" href="/">
|
||||
<div class="sidebar-brand-icon"><img src="/assets/img/favicon.png" width="44"></div>
|
||||
<div class="sidebar-brand-text mx-3"><span>FireWallet</span></div>
|
||||
</a>
|
||||
<hr class="sidebar-divider my-0">
|
||||
<ul class="navbar-nav text-light" id="accordionSidebar">
|
||||
<li class="nav-item"><a class="nav-link" href="/"><i class="fas fa-tachometer-alt"></i><span>Dashboard</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/tx"><i class="fas fa-table"></i><span>Transactions</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/send"><i class="material-icons">send</i><span>Send HNS</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/receive"><i class="material-icons">call_received</i><span>Receive</span></a></li>
|
||||
</ul>
|
||||
<div class="text-center d-none d-md-inline"><button class="btn rounded-circle border-0" id="sidebarToggle" type="button"></button></div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="d-flex flex-column" id="content-wrapper" style="background: var(--bs-primary);">
|
||||
<div id="content">
|
||||
<nav class="navbar navbar-expand shadow mb-4 topbar static-top navbar-light" style="background: var(--bs-primary-text-emphasis);">
|
||||
<div class="container-fluid"><button class="btn btn-link d-md-none rounded-circle me-3" id="sidebarToggleTop" type="button"><i class="fas fa-bars"></i></button>
|
||||
<form class="d-none d-sm-inline-block me-auto ms-md-3 my-2 my-md-0 mw-100 navbar-search" action="/search" method="get">
|
||||
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for domain" name="q" value="{{search_term}}"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
|
||||
</form><span>Sync: {{sync}}%</span>
|
||||
<ul class="navbar-nav flex-nowrap ms-auto">
|
||||
<li class="nav-item dropdown d-sm-none no-arrow"><a class="dropdown-toggle nav-link" aria-expanded="false" data-bs-toggle="dropdown" href="#"><i class="fas fa-search"></i></a>
|
||||
<div class="dropdown-menu dropdown-menu-end p-3 animated--grow-in" aria-labelledby="searchDropdown">
|
||||
<form class="me-auto navbar-search w-100">
|
||||
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ...">
|
||||
<div class="input-group-append"><button class="btn btn-primary py-0" type="button"><i class="fas fa-search"></i></button></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item dropdown no-arrow">
|
||||
<div class="nav-item dropdown no-arrow"><a class="dropdown-toggle nav-link" aria-expanded="false" data-bs-toggle="dropdown" href="#"><span class="d-none d-lg-inline me-2 small">{{account}}</span><img class="border rounded-circle img-profile" src="/assets/img/HNS.png"></a>
|
||||
<div class="dropdown-menu shadow dropdown-menu-end animated--grow-in"><a class="dropdown-item" href="/logout"><i class="fas fa-sign-out-alt fa-sm fa-fw me-2 text-gray-400"></i> Logout</a></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container-fluid">
|
||||
<h3 class="text-dark mb-1">Are you sure you want to do this?</h3>
|
||||
<div class="card" style="margin-top: 50px;">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">{{action}}</h4>
|
||||
<h6 class="text-muted card-subtitle mb-2">{{subtitle}}</h6>
|
||||
<p class="card-text">{{content|safe}}</p>
|
||||
<form method="post" action="{{confirm}}"><input class="form-control" type="password" name="password" placeholder="Password"><input class="btn btn-primary" type="submit" style="display: block;margin-top: 16px;margin-bottom: 16px;"><input class="form-control" type="hidden" name="check" value="{{check}}"></form><a class="card-link" href="{{cancel}}">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="sticky-footer" style="background: var(--bs-primary-text-emphasis);">
|
||||
<div class="container my-auto">
|
||||
<div class="text-center my-auto copyright"><span>Copyright © FireWallet 2024</span></div>
|
||||
</div>
|
||||
</footer>
|
||||
</div><a class="border rounded d-inline scroll-to-top" href="#page-top"><i class="fas fa-angle-up"></i></a>
|
||||
</div>
|
||||
<script src="/assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="/assets/js/script.min.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -91,7 +91,7 @@
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title" style="display: inline-block;">Transfer</h4>
|
||||
<form action="/manage/{{domain}}/transfer">
|
||||
<form action="/manage/{{domain}}/transfer" style="display: {% if finalize_time=='' %} block {% else %} none {% endif %};">
|
||||
<div style="margin-top: 25px;"><label class="form-label">Send to</label><input class="form-control" type="text" id="address" placeholder="Address or @domain" name="address" value="{{address}}"><span id="addressValid"></span><script>
|
||||
function checkAddress(inputValue) {
|
||||
// Make API request to "/checkaddress"
|
||||
@ -128,6 +128,10 @@ function checkAddress(inputValue) {
|
||||
inputField.addEventListener('blur', handleBlur);
|
||||
</script></div><input class="btn btn-primary" type="submit" value="Send" style="margin-top: 16px;">
|
||||
</form>
|
||||
<div style="display: {% if finalize_time=='' %} none {% else %} block {% endif %};">
|
||||
<h5>{{domain}}/ is transferring. You can finalize your transfer {{finalize_time}}. </h5>
|
||||
<div class="btn-group btn-group-lg" role="group"><a class="btn btn-primary" role="button" style="margin-right: 8px;margin-left: 8px;" href="/manage/{{domain}}/finalize">Finalize</a><a class="btn btn-primary" role="button" style="margin-right: 8px;margin-left: 8px;" href="/manage/{{domain}}/cancel">Cancel</a><a class="btn btn-primary" role="button" style="margin-right: 8px;margin-left: 8px;" href="/manage/{{domain}}/revoke">Revoke</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user