Compare commits
6 Commits
50164e9d5d
...
a877b5bf9e
| Author | SHA1 | Date | |
|---|---|---|---|
|
a877b5bf9e
|
|||
|
22d301581b
|
|||
|
a888a3bd55
|
|||
|
c247aef2d5
|
|||
|
0118200098
|
|||
|
7e861534a6
|
Binary file not shown.
14
README.md
14
README.md
@@ -35,13 +35,13 @@ Also available as a docker image:
|
||||
To run using a HSD running directly on the host:
|
||||
|
||||
```bash
|
||||
sudo docker run --network=host -e hsd_api=yourapikeyhere git.woodburn.au/nathanwoodburn/firewallet:latest
|
||||
sudo docker run --network=host -e HSD_API=yourapikeyhere git.woodburn.au/nathanwoodburn/firewallet:latest
|
||||
```
|
||||
|
||||
If you have HSD running on a different IP/container
|
||||
|
||||
```bash
|
||||
sudo docker run -p 5000:5000 -e hsd_api=yourapikeyhere -e hsd_ip=hsdcontainer git.woodburn.au/nathanwoodburn/firewallet:latest
|
||||
sudo docker run -p 5000:5000 -e HSD_API=yourapikeyhere -e HSD_IP=hsdcontainer git.woodburn.au/nathanwoodburn/firewallet:latest
|
||||
```
|
||||
|
||||
For Docker you can mount a volume to persist the user data (/app/user_data)
|
||||
@@ -115,11 +115,11 @@ Auction page
|
||||
## Environment variables
|
||||
|
||||
```yaml
|
||||
hsd_api: HSD API key
|
||||
hsd_ip: HSD IP address
|
||||
theme: Theme to use (dark-purple, black)
|
||||
show_expired: Show expired domains (true/false)
|
||||
exclude: Comma separated list of wallets to exclude from the wallet list
|
||||
HSD_API: HSD API key
|
||||
HSD_IP: HSD IP address
|
||||
THEME: Theme to use (dark-purple, black)
|
||||
SHOW_EXPIRED: Show expired domains (true/false)
|
||||
EXCLUDE: Comma separated list of wallets to exclude from the wallet list
|
||||
```
|
||||
|
||||
|
||||
|
||||
131
account.py
131
account.py
@@ -10,12 +10,12 @@ import time
|
||||
|
||||
dotenv.load_dotenv()
|
||||
|
||||
HSD_API = os.getenv("hsd_api")
|
||||
HSD_IP = os.getenv("hsd_ip")
|
||||
HSD_API = os.getenv("HSD_API")
|
||||
HSD_IP = os.getenv("HSD_IP")
|
||||
if HSD_IP is None:
|
||||
HSD_IP = "localhost"
|
||||
|
||||
HSD_NETWORK = os.getenv("hsd_network")
|
||||
HSD_NETWORK = os.getenv("HSD_NETWORK")
|
||||
HSD_WALLET_PORT = 12039
|
||||
HSD_NODE_PORT = 12037
|
||||
|
||||
@@ -35,9 +35,9 @@ elif HSD_NETWORK == "regtest":
|
||||
HSD_NODE_PORT = 14037
|
||||
|
||||
|
||||
show_expired = os.getenv("show_expired")
|
||||
if show_expired is None:
|
||||
show_expired = False
|
||||
SHOW_EXPIRED = os.getenv("SHOW_EXPIRED")
|
||||
if SHOW_EXPIRED is None:
|
||||
SHOW_EXPIRED = False
|
||||
|
||||
hsd = api.hsd(HSD_API,HSD_IP,HSD_NODE_PORT)
|
||||
hsw = api.hsw(HSD_API,HSD_IP,HSD_WALLET_PORT)
|
||||
@@ -47,9 +47,9 @@ cacheTime = 3600
|
||||
# Verify the connection
|
||||
response = hsd.getInfo()
|
||||
|
||||
exclude = ["primary"]
|
||||
if os.getenv("exclude") is not None:
|
||||
exclude = os.getenv("exclude").split(",")
|
||||
EXCLUDE = ["primary"]
|
||||
if os.getenv("EXCLUDE") is not None:
|
||||
EXCLUDE = os.getenv("EXCLUDE").split(",")
|
||||
|
||||
def hsdConnected():
|
||||
if hsdVersion() == -1:
|
||||
@@ -163,7 +163,7 @@ def listWallets():
|
||||
# Check if response is json or an array
|
||||
if isinstance(response, list):
|
||||
# Remove excluded wallets
|
||||
response = [wallet for wallet in response if wallet not in exclude]
|
||||
response = [wallet for wallet in response if wallet not in EXCLUDE]
|
||||
|
||||
return response
|
||||
return ['Wallet not connected']
|
||||
@@ -244,7 +244,7 @@ def getDomains(account,own=True):
|
||||
response = requests.get(f"http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}/wallet/{account}/name")
|
||||
info = response.json()
|
||||
|
||||
if show_expired:
|
||||
if SHOW_EXPIRED:
|
||||
return info
|
||||
|
||||
# Remove any expired domains
|
||||
@@ -433,6 +433,15 @@ def send(account,address,amount):
|
||||
"tx": response['result']
|
||||
}
|
||||
|
||||
def isOwnDomain(account,name: str):
|
||||
domains = getDomains(account)
|
||||
for domain in domains:
|
||||
print(domain)
|
||||
if domain['name'] == name:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def getDomain(domain: str):
|
||||
# Get the domain
|
||||
response = hsd.rpc_getNameInfo(domain)
|
||||
@@ -476,7 +485,6 @@ def getDNS(domain: str):
|
||||
return []
|
||||
return response['result']['records']
|
||||
|
||||
|
||||
def setDNS(account,domain,records):
|
||||
account_name = check_account(account)
|
||||
password = ":".join(account.split(":")[1:])
|
||||
@@ -521,6 +529,9 @@ def setDNS(account,domain,records):
|
||||
response = hsw.sendUPDATE(account_name,password,domain,data)
|
||||
return response
|
||||
|
||||
def register(account,domain):
|
||||
# Maybe add default dns records?
|
||||
return setDNS(account,domain,'[]')
|
||||
|
||||
def getNodeSync():
|
||||
response = hsd.getInfo()
|
||||
@@ -566,6 +577,43 @@ def getBids(account, domain="NONE"):
|
||||
def getReveals(account,domain):
|
||||
return hsw.getWalletRevealsByName(domain,account)
|
||||
|
||||
def getPendingReveals(account):
|
||||
bids = getBids(account)
|
||||
domains = getDomains(account,False)
|
||||
pending = []
|
||||
for domain in domains:
|
||||
if domain['state'] == "REVEAL":
|
||||
reveals = getReveals(account,domain['name'])
|
||||
for bid in bids:
|
||||
if bid['name'] == domain['name']:
|
||||
state_found = False
|
||||
for reveal in reveals:
|
||||
if reveal['own'] == True:
|
||||
if bid['value'] == reveal['value']:
|
||||
state_found = True
|
||||
|
||||
if not state_found:
|
||||
pending.append(bid)
|
||||
return pending
|
||||
|
||||
#! TODO
|
||||
def getPendingRedeems(account):
|
||||
bids = getBids(account)
|
||||
domains = getDomains(account,False)
|
||||
pending = []
|
||||
return pending
|
||||
|
||||
def getPendingRegisters(account):
|
||||
bids = getBids(account)
|
||||
domains = getDomains(account,False)
|
||||
pending = []
|
||||
for domain in domains:
|
||||
if domain['state'] == "CLOSED" and domain['registered'] == False:
|
||||
for bid in bids:
|
||||
if bid['name'] == domain['name']:
|
||||
if bid['value'] == domain['highest']:
|
||||
pending.append(bid)
|
||||
return pending
|
||||
|
||||
def getRevealTX(reveal):
|
||||
prevout = reveal['prevout']
|
||||
@@ -573,7 +621,11 @@ def getRevealTX(reveal):
|
||||
index = prevout['index']
|
||||
tx = hsd.getTxByHash(hash)
|
||||
if 'inputs' not in tx:
|
||||
# Check if registered
|
||||
print(f'Something is up with this tx: {hash}')
|
||||
print(tx)
|
||||
print('---')
|
||||
# No idea what happened here
|
||||
# Check if registered?
|
||||
return None
|
||||
return tx['inputs'][index]['prevout']['hash']
|
||||
|
||||
@@ -616,7 +668,6 @@ def revealAll(account):
|
||||
response = hsw.rpc_walletPassphrase(password,10)
|
||||
if response['error'] is not None:
|
||||
return
|
||||
# Try to send the batch of all renew, reveal and redeem actions
|
||||
|
||||
return requests.post(f"http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}",json={"method": "sendbatch","params": [[["REVEAL"]]]}).json()
|
||||
except Exception as e:
|
||||
@@ -626,6 +677,58 @@ def revealAll(account):
|
||||
}
|
||||
}
|
||||
|
||||
def redeemAll(account):
|
||||
account_name = check_account(account)
|
||||
password = ":".join(account.split(":")[1:])
|
||||
|
||||
if account_name == False:
|
||||
return {
|
||||
"error": {
|
||||
"message": "Invalid account"
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
# Try to select and login to the wallet
|
||||
response = hsw.rpc_selectWallet(account_name)
|
||||
if response['error'] is not None:
|
||||
return
|
||||
response = hsw.rpc_walletPassphrase(password,10)
|
||||
if response['error'] is not None:
|
||||
return
|
||||
|
||||
return requests.post(f"http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}",json={"method": "sendbatch","params": [[["REDEEM"]]]}).json()
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": {
|
||||
"message": str(e)
|
||||
}
|
||||
}
|
||||
|
||||
def registerAll(account):
|
||||
account_name = check_account(account)
|
||||
password = ":".join(account.split(":")[1:])
|
||||
|
||||
if account_name == False:
|
||||
return {
|
||||
"error": {
|
||||
"message": "Invalid account"
|
||||
}
|
||||
}
|
||||
|
||||
# try:
|
||||
domains = getPendingRegisters(account_name)
|
||||
if len(domains) == 0:
|
||||
return {
|
||||
"error": {
|
||||
"message": "Nothing to do."
|
||||
}
|
||||
}
|
||||
batch = []
|
||||
for domain in domains:
|
||||
batch.append(["UPDATE",domain['name'],{"records":[]}])
|
||||
return sendBatch(account,batch)
|
||||
|
||||
def rescan_auction(account,domain):
|
||||
# Get height of the start of the auction
|
||||
response = hsw.rpc_selectWallet(account)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
hsd_api=123480615465636893475aCwyaae6s45
|
||||
hsd_ip=localhost
|
||||
theme=black
|
||||
show_expired=false
|
||||
HSD_API=123480615465636893475aCwyaae6s45
|
||||
HSD_IP=localhost
|
||||
THEME=black
|
||||
SHOW_EXPIRED=false
|
||||
EXPLORER_TX=https://niami.io/tx/
|
||||
102
main.py
102
main.py
@@ -26,7 +26,7 @@ fees = 0.02
|
||||
revokeCheck = random.randint(100000,999999)
|
||||
|
||||
|
||||
theme = os.getenv("theme")
|
||||
THEME = os.getenv("THEME")
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
@@ -322,19 +322,7 @@ def auctions():
|
||||
bidsHtml = render.bidDomains(bids,domains)
|
||||
|
||||
|
||||
pending_reveals = 0
|
||||
for domain in domains:
|
||||
if domain['state'] == "REVEAL":
|
||||
for bid in bids:
|
||||
if bid['name'] == domain['name']:
|
||||
bid_found = False
|
||||
reveals = account_module.getReveals(account,domain['name'])
|
||||
for reveal in reveals:
|
||||
if reveal['own'] == True:
|
||||
if bid['value'] == reveal['value']:
|
||||
bid_found = True
|
||||
if not bid_found:
|
||||
pending_reveals += 1
|
||||
|
||||
|
||||
plugins = ""
|
||||
|
||||
@@ -347,10 +335,11 @@ def auctions():
|
||||
sort_state=sort_state,sort_domain=sort_domain,
|
||||
sort_price_next=sort_price_next,
|
||||
sort_state_next=sort_state_next,sort_domain_next=sort_domain_next,
|
||||
bids=len(bids),reveal=pending_reveals,message=message,
|
||||
bids=len(bids),message=message,
|
||||
sort_time=sort_time,sort_time_next=sort_time_next)
|
||||
|
||||
@app.route('/reveal')
|
||||
@app.route('/all/reveal')
|
||||
def revealAllBids():
|
||||
# Check if the user is logged in
|
||||
if request.cookies.get("account") is None:
|
||||
@@ -371,6 +360,46 @@ def revealAllBids():
|
||||
return redirect("/success?tx=" + response['result']['hash'])
|
||||
|
||||
|
||||
@app.route('/all/redeem')
|
||||
def redeemAllBids():
|
||||
# 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"))
|
||||
if not account:
|
||||
return redirect("/logout")
|
||||
|
||||
response = account_module.redeemAll(request.cookies.get("account"))
|
||||
if 'error' in response:
|
||||
print(response)
|
||||
if response['error'] != None:
|
||||
if response['error']['message'] == "Nothing to do.":
|
||||
return redirect("/auctions?message=No redeems pending")
|
||||
return redirect("/auctions?message=" + response['error']['message'])
|
||||
|
||||
return redirect("/success?tx=" + response['result']['hash'])
|
||||
|
||||
@app.route('/all/register')
|
||||
def registerAllDomains():
|
||||
# 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"))
|
||||
if not account:
|
||||
return redirect("/logout")
|
||||
|
||||
response = account_module.registerAll(request.cookies.get("account"))
|
||||
if 'error' in response:
|
||||
print(response)
|
||||
if response['error'] != None:
|
||||
if response['error']['message'] == "Nothing to do.":
|
||||
return redirect("/auctions?message=No domains to register")
|
||||
return redirect("/auctions?message=" + response['error']['message'])
|
||||
|
||||
return redirect("/success?tx=" + response['hash'])
|
||||
|
||||
@app.route('/search')
|
||||
def search():
|
||||
# Check if the user is logged in
|
||||
@@ -845,6 +874,10 @@ def auction(domain):
|
||||
error=error)
|
||||
|
||||
if domainInfo['info'] is None:
|
||||
if domainInfo['registered'] == False and domainInfo['expired'] == False:
|
||||
# Needs to be registered
|
||||
next_action = f'ERROR GETTING NEXT STATE'
|
||||
else:
|
||||
next_action = f'<a href="/auction/{domain}/open">Open Auction</a>'
|
||||
return render_template("auction.html", account=account,
|
||||
|
||||
@@ -871,6 +904,14 @@ def auction(domain):
|
||||
|
||||
if state == 'CLOSED':
|
||||
if not domainInfo['info']['registered']:
|
||||
if account_module.isOwnDomain(account,domain):
|
||||
print("Waiting to be registered")
|
||||
state = 'PENDING REGISTER'
|
||||
next = "Pending Register"
|
||||
next_action = f'<a href="/auction/{domain}/register">Register Domain</a>'
|
||||
|
||||
else:
|
||||
print("Not registered")
|
||||
state = 'AVAILABLE'
|
||||
next = "Available Now"
|
||||
next_action = f'<a href="/auction/{domain}/open">Open Auction</a>'
|
||||
@@ -1030,7 +1071,22 @@ def reveal_auction(domain):
|
||||
return redirect("/logout")
|
||||
|
||||
domain = domain.lower()
|
||||
response = account_module.revealAuction(request.cookies.get("account"),domain)
|
||||
response = account_module(request.cookies.get("account"),domain)
|
||||
if 'error' in response:
|
||||
return redirect("/auction/" + domain + "?message=" + response['error']['message'])
|
||||
return redirect("/success?tx=" + response['hash'])
|
||||
|
||||
@app.route('/auction/<domain>/register')
|
||||
def registerdomain(domain):
|
||||
# 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()
|
||||
response = account_module.register(request.cookies.get("account"),domain)
|
||||
if 'error' in response:
|
||||
return redirect("/auction/" + domain + "?message=" + response['error']['message'])
|
||||
return redirect("/success?tx=" + response['hash'])
|
||||
@@ -1450,6 +1506,16 @@ def api_wallet(function):
|
||||
if function == "domainCount":
|
||||
return jsonify({"result": len(account_module.getDomains(account))})
|
||||
|
||||
if function == "bidCount":
|
||||
return jsonify({"result": len(account_module.getBids(account))})
|
||||
|
||||
if function == "pendingReveal":
|
||||
return jsonify({"result": len(account_module.getPendingReveals(account))})
|
||||
if function == "pendingRegister":
|
||||
return jsonify({"result": len(account_module.getPendingRegisters(account))})
|
||||
if function == "pendingRedeem":
|
||||
return jsonify({"result": len(account_module.getPendingRedeems(account))})
|
||||
|
||||
|
||||
return jsonify({"error": "Invalid function", "result": "Invalid function"}), 400
|
||||
|
||||
@@ -1466,9 +1532,9 @@ def qr(data):
|
||||
# Theme
|
||||
@app.route('/assets/css/styles.min.css')
|
||||
def send_css():
|
||||
if theme == "live":
|
||||
if THEME == "live":
|
||||
return send_from_directory('templates/assets/css', 'styles.min.css')
|
||||
return send_from_directory('themes', f'{theme}.css')
|
||||
return send_from_directory('themes', f'{THEME}.css')
|
||||
|
||||
@app.route('/assets/<path:path>')
|
||||
def send_assets(path):
|
||||
|
||||
67
render.py
67
render.py
@@ -3,6 +3,14 @@ import json
|
||||
import urllib.parse
|
||||
from flask import render_template
|
||||
from domainLookup import punycode_to_emoji
|
||||
import os
|
||||
|
||||
# Get Explorer URL
|
||||
TX_EXPLORER_URL = os.getenv("EXPLORER_TX")
|
||||
if TX_EXPLORER_URL is None:
|
||||
TX_EXPLORER_URL = "https://niami.io/tx/"
|
||||
|
||||
|
||||
|
||||
def domains(domains, mobile=False):
|
||||
html = ''
|
||||
@@ -21,10 +29,17 @@ def domains(domains, mobile=False):
|
||||
if emoji != name:
|
||||
name = f'{emoji} ({name})'
|
||||
|
||||
|
||||
link = f'/manage/{domain["name"]}'
|
||||
link_action = "Manage"
|
||||
if domain['registered'] == False:
|
||||
link_action = "Register"
|
||||
link = f'/auction/{domain["name"]}/register'
|
||||
|
||||
if not mobile:
|
||||
html += f'<tr><td>{name}</td><td>{expires} days</td><td>{paid} HNS</td><td><a href="/manage/{domain["name"]}">Manage</a></td></tr>'
|
||||
html += f'<tr><td>{name}</td><td>{expires} days</td><td>{paid:,.2f} HNS</td><td><a href="{link}">{link_action}</a></td></tr>'
|
||||
else:
|
||||
html += f'<tr><td><a href="/manage/{domain["name"]}">{name}</a></td><td>{expires} days</td></tr>'
|
||||
html += f'<tr><td><a href="{link}">{name}</a></td><td>{expires} days</td></tr>'
|
||||
|
||||
return html
|
||||
|
||||
@@ -58,17 +73,15 @@ def transactions(txs):
|
||||
amount += output["value"]
|
||||
|
||||
amount = amount / 1000000
|
||||
amount = round(amount, 2)
|
||||
amount = "{:,}".format(amount)
|
||||
|
||||
hash = "<a target='_blank' href='https://niami.io/tx/" + hash + "'>" + hash[:8] + "...</a>"
|
||||
hash = f"<a target='_blank' href='{TX_EXPLORER_URL}{hash}'>{hash[:8]}...</a>"
|
||||
if confirmations < 5:
|
||||
confirmations = "<td style='background-color: red;'>" + str(confirmations) + "</td>"
|
||||
confirmations = f"<td style='background-color: red;'>{confirmations}</td>"
|
||||
else:
|
||||
confirmations = "<td>" + str(confirmations) + "</td>"
|
||||
confirmations = f"<td>{confirmations:,}</td>"
|
||||
|
||||
|
||||
html += f'<tr><td>{action}</td><td>{address}</td><td>{hash}</td>{confirmations}<td>{amount} HNS</td></tr>'
|
||||
html += f'<tr><td>{action}</td><td>{address}</td><td>{hash}</td>{confirmations}<td>{amount:,.2f} HNS</td></tr>'
|
||||
return html
|
||||
|
||||
|
||||
@@ -92,14 +105,14 @@ def dns(data, edit=False):
|
||||
|
||||
|
||||
elif entry['type'] == 'DS':
|
||||
ds = str(entry['keyTag']) + " " + str(entry['algorithm']) + " " + str(entry['digestType']) + " " + entry['digest']
|
||||
ds = f'{entry['keyTag']} {entry['algorithm']} {entry['digestType']} {entry['digest']}'
|
||||
html_output += f"<td>{ds}</td>\n"
|
||||
|
||||
else:
|
||||
value = ""
|
||||
for key, val in entry.items():
|
||||
if key != 'type':
|
||||
value += str(val) + " "
|
||||
value += f'{val} '
|
||||
html_output += f"<td>{value}</td>\n"
|
||||
|
||||
if edit:
|
||||
@@ -119,18 +132,16 @@ def txs(data):
|
||||
|
||||
for entry in data:
|
||||
html_output += f"<tr><td>{entry['action']}</td>\n"
|
||||
html_output += f"<td><a target='_blank' href='https://niami.io/tx/{entry['txid']}'>{entry['txid'][:8]}...</a></td>\n"
|
||||
html_output += f"<td><a target='_blank' href='{TX_EXPLORER_URL}{entry['txid']}'>{entry['txid'][:8]}...</a></td>\n"
|
||||
amount = entry['amount']
|
||||
amount = amount / 1000000
|
||||
amount = round(amount, 2)
|
||||
|
||||
if entry['blind'] == None:
|
||||
html_output += f"<td>{amount} HNS</td>\n"
|
||||
html_output += f"<td>{amount:,.2f} HNS</td>\n"
|
||||
else:
|
||||
blind = entry['blind']
|
||||
blind = blind / 1000000
|
||||
blind = round(blind, 2)
|
||||
html_output += f"<td>{amount} + {blind} HNS</td>\n"
|
||||
html_output += f"<td>{amount:,.2f} + {blind:,.2f} HNS</td>\n"
|
||||
|
||||
html_output += f"<td>{timestamp_to_readable_time(entry['time'])}</td>\n"
|
||||
html_output += f"</tr>\n"
|
||||
@@ -149,20 +160,17 @@ def bids(bids,reveals):
|
||||
for bid in bids:
|
||||
lockup = bid['lockup']
|
||||
lockup = lockup / 1000000
|
||||
lockup = round(lockup, 2)
|
||||
html += "<tr>"
|
||||
html += f"<td>{lockup} HNS</td>"
|
||||
html += f"<td>{lockup:,.2f} HNS</td>"
|
||||
revealed = False
|
||||
for reveal in reveals:
|
||||
if reveal['bid'] == bid['prevout']['hash']:
|
||||
revealed = True
|
||||
value = reveal['value']
|
||||
value = value / 1000000
|
||||
value = round(value, 2)
|
||||
html += f"<td>{value} HNS</td>"
|
||||
html += f"<td>{value:,.2f} HNS</td>"
|
||||
bidValue = lockup - value
|
||||
bidValue = round(bidValue, 2)
|
||||
html += f"<td>{bidValue} HNS</td>"
|
||||
html += f"<td>{bidValue:,.2f} HNS</td>"
|
||||
break
|
||||
if not revealed:
|
||||
html += f"<td>Hidden until reveal</td>"
|
||||
@@ -183,22 +191,17 @@ def bidDomains(bids,domains, sortState=False):
|
||||
if bid['name'] == domain['name']:
|
||||
lockup = bid['lockup']
|
||||
lockup = lockup / 1000000
|
||||
lockup = round(lockup, 2)
|
||||
bidValue = bid['value'] / 1000000
|
||||
bidValue = round(bidValue, 2)
|
||||
blind = lockup - bidValue
|
||||
bidValue = "{:,}".format(bidValue)
|
||||
blind = round(blind, 2)
|
||||
blind = "{:,}".format(blind)
|
||||
|
||||
bidDisplay = f'<b>{bidValue} HNS</b> + {blind} HNS blind'
|
||||
bidDisplay = f'<b>{bidValue:,.2f} HNS</b> + {blind:,.2f} HNS blind'
|
||||
|
||||
|
||||
html += "<tr>"
|
||||
html += f"<td><a class='text-decoration-none' style='color: var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));' href='/auction/{domain['name']}'>{domain['name']}</a></td>"
|
||||
html += f"<td>{domain['state']}</td>"
|
||||
html += f"<td>{bidDisplay}</td>"
|
||||
html += f"<td>{bid['height']}</td>"
|
||||
html += f"<td>{bid['height']:,}</td>"
|
||||
html += "</tr>"
|
||||
else:
|
||||
for domain in domains:
|
||||
@@ -206,19 +209,15 @@ def bidDomains(bids,domains, sortState=False):
|
||||
if bid['name'] == domain['name']:
|
||||
lockup = bid['lockup']
|
||||
lockup = lockup / 1000000
|
||||
lockup = round(lockup, 2)
|
||||
bidValue = bid['value'] / 1000000
|
||||
bidValue = round(bidValue, 2)
|
||||
blind = lockup - bidValue
|
||||
bidValue = "{:,}".format(bidValue)
|
||||
blind = "{:,}".format(blind)
|
||||
|
||||
bidDisplay = f'<b>{bidValue} HNS</b> + {blind} HNS blind'
|
||||
bidDisplay = f'<b>{bidValue:,.2f} HNS</b> + {blind:,.2f} HNS blind'
|
||||
html += "<tr>"
|
||||
html += f"<td><a class='text-decoration-none' style='color: var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));' href='/auction/{domain['name']}'>{domain['name']}</a></td>"
|
||||
html += f"<td>{domain['state']}</td>"
|
||||
html += f"<td>{bidDisplay}</td>"
|
||||
html += f"<td>{domain['height']}</td>"
|
||||
html += f"<td>{domain['height']:,}</td>"
|
||||
html += "</tr>"
|
||||
return html
|
||||
|
||||
|
||||
2
templates/assets/js/script.min.js
vendored
2
templates/assets/js/script.min.js
vendored
@@ -1 +1 @@
|
||||
async function request(e){try{const t=await fetch(`/api/v1/${e}`);if(!t.ok)throw new Error(`HTTP error! Status: ${t.status}`);const o=await t.json();return void 0!==o.error?`Error: ${o.error}`:o.result}catch(e){return console.error("Request failed:",e),"Error"}}window.addEventListener("load",(async()=>{const e=["hsd-sync","hsd-version","hsd-height","wallet-sync","wallet-available","wallet-total","wallet-locked","wallet-pending","wallet-domainCount"],t=["wallet-available","wallet-total","wallet-locked","wallet-pending"];for(const o of e){const e=document.getElementById(o);if(e){const l=o.replace(/-/g,"/");let n=await request(l);t.includes(o)&&(n=Number(n).toFixed(2),n=n.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")),e.innerHTML=n}}})),function(){"use strict";var e=document.querySelector(".sidebar"),t=document.querySelectorAll("#sidebarToggle, #sidebarToggleTop");if(e){e.querySelector(".collapse");var o=[].slice.call(document.querySelectorAll(".sidebar .collapse")).map((function(e){return new bootstrap.Collapse(e,{toggle:!1})}));for(var l of t)l.addEventListener("click",(function(t){if(document.body.classList.toggle("sidebar-toggled"),e.classList.toggle("toggled"),e.classList.contains("toggled"))for(var l of o)l.hide()}));window.addEventListener("resize",(function(){if(Math.max(document.documentElement.clientWidth||0,window.innerWidth||0)<768)for(var e of o)e.hide()}))}var n=document.querySelector("body.fixed-nav .sidebar");n&&n.on("mousewheel DOMMouseScroll wheel",(function(e){if(Math.max(document.documentElement.clientWidth||0,window.innerWidth||0)>768){var t=e.originalEvent,o=t.wheelDelta||-t.detail;this.scrollTop+=30*(o<0?1:-1),e.preventDefault()}}));var r=document.querySelector(".scroll-to-top");r&&window.addEventListener("scroll",(function(){var e=window.pageYOffset;r.style.display=e>100?"block":"none"}))}();
|
||||
async function request(e){try{const t=await fetch(`/api/v1/${e}`);if(!t.ok)throw new Error(`HTTP error! Status: ${t.status}`);const l=await t.json();return void 0!==l.error?`Error: ${l.error}`:l.result}catch(e){return console.error("Request failed:",e),"Error"}}window.addEventListener("load",(async()=>{const e=["hsd-sync","hsd-version","hsd-height","wallet-sync","wallet-available","wallet-total","wallet-locked","wallet-pending","wallet-domainCount","wallet-bidCount","wallet-pendingReveal","wallet-pendingRegister","wallet-pendingRedeem"],t=["wallet-available","wallet-total","wallet-locked","wallet-pending"];for(const l of e){const e=document.getElementById(l);if(e){const o=l.replace(/-/g,"/");let n=await request(o);t.includes(l)&&(n=Number(n).toFixed(2),n=n.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")),e.innerHTML=n}}})),function(){"use strict";var e=document.querySelector(".sidebar"),t=document.querySelectorAll("#sidebarToggle, #sidebarToggleTop");if(e){e.querySelector(".collapse");var l=[].slice.call(document.querySelectorAll(".sidebar .collapse")).map((function(e){return new bootstrap.Collapse(e,{toggle:!1})}));for(var o of t)o.addEventListener("click",(function(t){if(document.body.classList.toggle("sidebar-toggled"),e.classList.toggle("toggled"),e.classList.contains("toggled"))for(var o of l)o.hide()}));window.addEventListener("resize",(function(){if(Math.max(document.documentElement.clientWidth||0,window.innerWidth||0)<768)for(var e of l)e.hide()}))}var n=document.querySelector("body.fixed-nav .sidebar");n&&n.on("mousewheel DOMMouseScroll wheel",(function(e){if(Math.max(document.documentElement.clientWidth||0,window.innerWidth||0)>768){var t=e.originalEvent,l=t.wheelDelta||-t.detail;this.scrollTop+=30*(l<0?1:-1),e.preventDefault()}}));var r=document.querySelector(".scroll-to-top");r&&window.addEventListener("scroll",(function(){var e=window.pageYOffset;r.style.display=e>100?"block":"none"}))}();
|
||||
@@ -87,7 +87,7 @@
|
||||
<div class="row align-items-center no-gutters">
|
||||
<div class="col me-2">
|
||||
<div class="text-uppercase text-success fw-bold text-xs mb-1"><span>Total Bids</span></div>
|
||||
<div class="text-dark fw-bold h5 mb-0"><span>{{bids}}</span></div>
|
||||
<div class="text-dark fw-bold h5 mb-0"><span id="wallet-bidCount">0</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -101,9 +101,43 @@
|
||||
<div class="text-uppercase text-info fw-bold text-xs mb-1"><span>Pending Reveal</span></div>
|
||||
<div class="row g-0 align-items-center">
|
||||
<div class="col-auto">
|
||||
<div class="text-dark fw-bold h5 mb-0 me-3"><span>{{reveal}}</span></div>
|
||||
<div class="text-dark fw-bold h5 mb-0 me-3"><span id="wallet-pendingReveal">0</span></div>
|
||||
</div>
|
||||
<div class="col"><a class="btn btn-primary" role="button" href="/reveal">Reveal All</a></div>
|
||||
<div class="col"><a class="btn btn-primary" role="button" href="/all/reveal">Reveal All</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-xl-3 mb-4">
|
||||
<div class="card shadow border-start-info py-2">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center no-gutters">
|
||||
<div class="col me-2">
|
||||
<div class="text-uppercase text-info fw-bold text-xs mb-1"><span>Pending Redeem</span></div>
|
||||
<div class="row g-0 align-items-center">
|
||||
<div class="col-auto">
|
||||
<div class="text-dark fw-bold h5 mb-0 me-3"><span id="wallet-pendingRedeem">0</span></div>
|
||||
</div>
|
||||
<div class="col"><a class="btn btn-primary" role="button" href="/all/redeem">Redeem All</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-xl-3 mb-4">
|
||||
<div class="card shadow border-start-info py-2">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center no-gutters">
|
||||
<div class="col me-2">
|
||||
<div class="text-uppercase text-info fw-bold text-xs mb-1"><span>Pending Register</span></div>
|
||||
<div class="row g-0 align-items-center">
|
||||
<div class="col-auto">
|
||||
<div class="text-dark fw-bold h5 mb-0 me-3"><span id="wallet-pendingRegister">0</span></div>
|
||||
</div>
|
||||
<div class="col"><a class="btn btn-primary" role="button" href="/all/register">Register All</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user