Compare commits

..

No commits in common. "main" and "feat/plugins" have entirely different histories.

62 changed files with 618 additions and 8050 deletions

12
.gitignore vendored
View File

@ -1,16 +1,6 @@
.env
.env*
__pycache__/
templates/assets/css/styles.min.css
ignore/
plugins/signatures.json
.venv/
user_data/
customPlugins/
cache/

View File

@ -10,7 +10,6 @@ COPY . /app
# Add mount point for data volume
# VOLUME /data
RUN apk add git openssl
ENTRYPOINT ["python3"]
CMD ["server.py"]

Binary file not shown.

View File

@ -1,7 +1,7 @@
# FireWalletBrowser
## Installation
See [here](https://firewallet.au/setup) for instructions on how to setup a FireWallet
## Installation
```bash
git clone https://github.com/Nathanwoodburn/firewalletbrowser.git
@ -17,37 +17,29 @@ If you have HSD runnning on a separate computer also add the IP here
Make sure HSD is running then run the following commands:
On Linux:
```bash
python3 server.py
# Or for more verbose output
python3 main.py
```
On Windows:
```bash
python3 main.py
```
Then access the wallet at http://localhost:5000
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)
## Features
- Basic wallet functionality
- Create new wallet
@ -72,7 +64,7 @@ For Docker you can mount a volume to persist the user data (/app/user_data)
- Rescan
- Zap pending transactions
- View xPub
- Custom plugin support (find some [here](https://git.woodburn.au/nathanwoodburn?tab=repositories&q=plugin&sort=recentupdate))
- Custom plugin support
## Themes
Set a theme in the .env file
@ -112,24 +104,4 @@ DNS Editor page
![DNS Editor page](assets/dnseditor.png)
Auction page
![Auction page](assets/auction.png)
## 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 (default primary)
EXPLORER_TX: URL for exploring transactions (default https://niami.io/tx/)
HSD_NETWORK: Network to connect to (main, regtest, simnet)
```
## Warnings
- This is a work in progress and is not guaranteed to work
- This is not a wallet by itself but rather a frontend for HSD
- I am not responsible for any loss of funds from using this wallet (including loss of funds from auctions)
- I am not responsible if you expose this frontend to the internet (please don't do this unless you know what you are doing)
![Auction page](assets/auction.png)

View File

@ -6,64 +6,24 @@ import requests
import re
import domainLookup
import json
import time
dotenv.load_dotenv()
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_WALLET_PORT = 12039
HSD_NODE_PORT = 12037
if not HSD_NETWORK:
HSD_NETWORK = "main"
else:
HSD_NETWORK = HSD_NETWORK.lower()
if HSD_NETWORK == "simnet":
HSD_WALLET_PORT = 15039
HSD_NODE_PORT = 15037
elif HSD_NETWORK == "testnet":
HSD_WALLET_PORT = 13039
HSD_NODE_PORT = 13037
elif HSD_NETWORK == "regtest":
HSD_WALLET_PORT = 14039
HSD_NODE_PORT = 14037
APIKEY = os.getenv("hsd_api")
ip = os.getenv("hsd_ip")
if ip is None:
ip = "localhost"
SHOW_EXPIRED = os.getenv("SHOW_EXPIRED")
if SHOW_EXPIRED is None:
SHOW_EXPIRED = False
hsd = api.hsd(APIKEY,ip)
hsw = api.hsw(APIKEY,ip)
hsd = api.hsd(HSD_API,HSD_IP,HSD_NODE_PORT)
hsw = api.hsw(HSD_API,HSD_IP,HSD_WALLET_PORT)
cacheTime = 3600
# Verify the connection
response = hsd.getInfo()
EXCLUDE = ["primary"]
if os.getenv("EXCLUDE") is not None:
EXCLUDE = os.getenv("EXCLUDE").split(",")
def hsdConnected():
if hsdVersion() == -1:
return False
return True
def hsdVersion(format=True):
info = hsd.getInfo()
if 'error' in info:
return -1
if format:
return float('.'.join(info['version'].split(".")[:2]))
else:
return info['version']
def check_account(cookie: str):
if cookie is None:
@ -89,22 +49,18 @@ def check_password(cookie: str, password: str):
info = hsw.rpc_selectWallet(account)
if info['error'] is not None:
return False
info = hsw.rpc_walletPassphrase(password,1)
info = hsw.rpc_walletPassphrase(password,10)
if info['error'] is not None:
if info['error']['message'] != "Wallet is not encrypted.":
return False
return False
return True
def createWallet(account: str, password: str):
if not hsdConnected():
return {
"error": {
"message": "Node not connected"
}
}
# Create the account
# Python wrapper doesn't support this yet
response = requests.put(f"http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}/wallet/{account}")
response = requests.put(f"http://x:{APIKEY}@{ip}:12039/wallet/{account}")
print(response)
print(response.json())
if response.status_code != 200:
return {
"error": {
@ -118,8 +74,9 @@ def createWallet(account: str, password: str):
# Encrypt the wallet (python wrapper doesn't support this yet)
response = requests.post(f"http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}/wallet/{account}/passphrase",
response = requests.post(f"http://x:{APIKEY}@{ip}:12039/wallet/{account}/passphrase",
json={"passphrase": password})
print(response)
return {
"seed": seed,
@ -128,20 +85,16 @@ def createWallet(account: str, password: str):
}
def importWallet(account: str, password: str,seed: str):
if not hsdConnected():
return {
"error": {
"message": "Node not connected"
}
}
# Import the wallet
data = {
"passphrase": password,
"mnemonic": seed,
}
response = requests.put(f"http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}/wallet/{account}",json=data)
response = requests.put(f"http://x:{APIKEY}@{ip}:12039/wallet/{account}",json=data)
print(response)
print(response.json())
if response.status_code != 200:
return {
"error": {
@ -162,22 +115,9 @@ 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]
return response
return ['Wallet not connected']
def selectWallet(account: str):
# Select wallet
response = hsw.rpc_selectWallet(account)
if response['error'] is not None:
return {
"error": {
"message": response['error']['message']
}
}
def getBalance(account: str):
# Get the total balance
info = hsw.getBalance('default',account)
@ -186,26 +126,16 @@ def getBalance(account: str):
total = info['confirmed']
available = total - info['lockedConfirmed']
locked = info['lockedConfirmed'] / 1000000
# Convert to HNS
total = total / 1000000
available = available / 1000000
domains = getDomains(account)
domainValue = 0
for domain in domains:
if domain['state'] == "CLOSED":
domainValue += domain['value']
total = total - (domainValue/1000000)
locked = locked - (domainValue/1000000)
# Only keep 2 decimal places
total = round(total, 2)
available = round(available, 2)
return {'available': available, 'total': total, 'locked': locked}
return {'available': available, 'total': total}
def getBlockHeight():
# Get the block height
@ -222,136 +152,35 @@ def getAddress(account: str):
return info['receiveAddress']
def getPendingTX(account: str):
# Get the pending transactions
info = hsw.getWalletTxHistory(account)
if 'error' in info:
return 0
pending = 0
page = 1
pageSize = 10
while True:
txs = getTransactions(account,page,pageSize)
page+=1
pendingPage = 0
for tx in txs:
if tx['confirmations'] < 1:
pending+=1
pendingPage+=1
if pendingPage < pageSize:
break
for tx in info:
if tx['confirmations'] < 1:
pending += 1
return pending
def getDomains(account,own=True):
if own:
response = requests.get(f"http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}/wallet/{account}/name?own=true")
else:
response = requests.get(f"http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}/wallet/{account}/name")
def getDomains(account):
# Get the domains
# info = hsw.getWalletNames(account)
# if 'error' in info:
# return []
# use requests to get the domains
response = requests.get(f"http://x:{APIKEY}@{ip}:12039/wallet/{account}/name?own=true")
info = response.json()
return info
if SHOW_EXPIRED:
return info
# Remove any expired domains
domains = []
for domain in info:
if 'stats' in domain:
if 'daysUntilExpire' in domain['stats']:
if domain['stats']['daysUntilExpire'] < 0:
continue
domains.append(domain)
return domains
def getPageTXCache(account,page,size=100):
page = f"{page}-{size}"
if not os.path.exists(f'cache'):
os.mkdir(f'cache')
if not os.path.exists(f'cache/{account}_page.json'):
with open(f'cache/{account}_page.json', 'w') as f:
f.write('{}')
with open(f'cache/{account}_page.json') as f:
pageCache = json.load(f)
if page in pageCache and pageCache[page]['time'] > int(time.time()) - cacheTime:
return pageCache[page]['txid']
return None
def pushPageTXCache(account,page,txid,size=100):
page = f"{page}-{size}"
if not os.path.exists(f'cache/{account}_page.json'):
with open(f'cache/{account}_page.json', 'w') as f:
f.write('{}')
with open(f'cache/{account}_page.json') as f:
pageCache = json.load(f)
pageCache[page] = {
'time': int(time.time()),
'txid': txid
}
with open(f'cache/{account}_page.json', 'w') as f:
json.dump(pageCache, f,indent=4)
return pageCache[page]['txid']
def getTXFromPage(account,page,size=100):
if page == 1:
return getTransactions(account,1,size)[-1]['hash']
cached = getPageTXCache(account,page,size)
if cached:
return getPageTXCache(account,page,size)
previous = getTransactions(account,page,size)
if len(previous) == 0:
return None
hash = previous[-1]['hash']
pushPageTXCache(account,page,hash,size)
return hash
def getTransactions(account,page=1,limit=100):
def getTransactions(account):
# Get the transactions
if hsdVersion() < 7:
if page != 1:
return []
info = hsw.getWalletTxHistory(account)
if 'error' in info:
return []
return info[::-1]
lastTX = None
if page < 1:
return []
if page > 1:
lastTX = getTXFromPage(account,page-1,limit)
if lastTX:
response = requests.get(f'http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}/wallet/{account}/tx/history?reverse=true&limit={limit}&after={lastTX}')
elif page == 1:
response = requests.get(f'http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}/wallet/{account}/tx/history?reverse=true&limit={limit}')
else:
info = hsw.getWalletTxHistory(account)
if 'error' in info:
return []
return info
if response.status_code != 200:
print(response.text)
return []
data = response.json()
# Refresh the cache if the next page is different
nextPage = getPageTXCache(account,page,limit)
if nextPage is not None and nextPage != data[-1]['hash']:
print(f'Refreshing page {page}')
pushPageTXCache(account,page,data[-1]['hash'],limit)
return data
def getAllTransactions(account):
# Get the transactions
page = 0
txs = []
while True:
txs += getTransactions(account,page,1000)
if len(txs) == 0:
break
page += 1
return txs
def check_address(address: str, allow_name: bool = True, return_address: bool = False):
# Check if the address is valid
@ -364,7 +193,7 @@ def check_address(address: str, allow_name: bool = True, return_address: bool =
return check_hip2(address[1:])
# Check if the address is a valid HNS address
response = requests.post(f"http://x:{HSD_API}@{HSD_IP}:{HSD_NODE_PORT}",json={
response = requests.post(f"http://x:{APIKEY}@{ip}:12037",json={
"method": "validateaddress",
"params": [address]
}).json()
@ -388,7 +217,7 @@ def check_hip2(domain: str):
domain = domain.lower()
if re.match(r'^[a-zA-Z0-9\-\.]{1,63}$', domain) is None:
return 'Invalid domain'
return 'Invalid address'
address = domainLookup.hip2(domain)
if address.startswith("Hip2: "):
@ -403,6 +232,10 @@ def check_hip2(domain: str):
def send(account,address,amount):
account_name = check_account(account)
password = ":".join(account.split(":")[1:])
response = hsw.rpc_selectWallet(account_name)
if response['error'] is not None:
return {
@ -413,7 +246,7 @@ def send(account,address,amount):
response = hsw.rpc_walletPassphrase(password,10)
# Unlock the account
# response = requests.post(f"http://x:{APIKEY}@{ip}:{HSD_WALLET_PORT}/wallet/{account_name}/unlock",
# response = requests.post(f"http://x:{APIKEY}@{ip}:12039/wallet/{account_name}/unlock",
# json={"passphrase": password,"timeout": 10})
if response['error'] is not None:
return {
@ -433,15 +266,6 @@ 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)
@ -474,17 +298,9 @@ def getDNS(domain: str):
return {
"error": response['error']['message']
}
if 'result' not in response:
return {
"error": "No DNS records"
}
if response['result'] == None:
return []
if 'records' not in response['result']:
return []
return response['result']['records']
def setDNS(account,domain,records):
account_name = check_account(account)
password = ":".join(account.split(":")[1:])
@ -501,11 +317,7 @@ def setDNS(account,domain,records):
TXTRecords = []
for record in records:
if record['type'] == 'TXT':
if 'txt' not in record:
TXTRecords.append(record['value'])
else:
for txt in record['txt']:
TXTRecords.append(txt)
TXTRecords.append(record['value'])
elif record['type'] == 'NS':
newRecords.append({
'type': 'NS',
@ -524,14 +336,12 @@ def setDNS(account,domain,records):
newRecords.append({
'type': 'TXT',
'txt': TXTRecords
})
})
data = '{"records":'+str(newRecords).replace("'","\"")+'}'
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()
@ -542,139 +352,20 @@ def getNodeSync():
sync = round(sync, 2)
return sync
def getWalletStatus():
response = hsw.rpc_getWalletInfo()
if 'error' in response and response['error'] != None:
return "Error"
# return response
walletHeight = response['result']['height']
# Get the current block height
nodeHeight = getBlockHeight()
if walletHeight < nodeHeight:
return f"Scanning {walletHeight/nodeHeight*100:.2f}%"
elif walletHeight == nodeHeight:
return "Ready"
else:
return "Error wallet ahead of node"
def getBids(account, domain="NONE"):
if domain == "NONE":
response = hsw.getWalletBids(account)
else:
response = hsw.getWalletBidsByName(domain,account)
# Add backup for bids with no value
bids = []
for bid in response:
if 'value' not in bid:
bid['value'] = -1000000
# Backup for older HSD versions
if 'height' not in bid:
bid['height'] = 0
bids.append(bid)
return bids
def getBids(account, domain):
response = hsw.getWalletBidsByName(domain,account)
return response
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
def getPendingRedeems(account,password):
hsw.rpc_selectWallet(account)
hsw.rpc_walletPassphrase(password,10)
tx = hsw.rpc_createREDEEM('','default')
if tx['error']:
return []
pending = []
try:
for output in tx['result']['outputs']:
if output['covenant']['type'] != 5:
continue
if output['covenant']['action'] != "REDEEM":
continue
nameHash = output['covenant']['items'][0]
# Try to get the name from hash
name = hsd.rpc_getNameByHash(nameHash)
if name['error']:
pending.append(nameHash)
else:
pending.append(name['result'])
except:
print("Failed to parse redeems")
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 getPendingFinalizes(account,password):
tx = createBatch(f'{account}:{password}',[["FINALIZE"]])
if 'error' in tx:
return []
pending = []
try:
for output in tx['outputs']:
if output['covenant']['type'] != 10:
continue
if output['covenant']['action'] != "FINALIZE":
continue
nameHash = output['covenant']['items'][0]
# Try to get the name from hash
name = hsd.rpc_getNameByHash(nameHash)
if name['error']:
pending.append(nameHash)
else:
pending.append(name['result'])
except:
print("Failed to parse finalizes")
return pending
def getRevealTX(reveal):
prevout = reveal['prevout']
hash = prevout['hash']
index = prevout['index']
tx = hsd.getTxByHash(hash)
if 'inputs' not in tx:
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']
@ -697,99 +388,6 @@ def revealAuction(account,domain):
"error": str(e)
}
def revealAll(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": [[["REVEAL"]]]}).json()
except Exception as e:
return {
"error": {
"message": str(e)
}
}
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 finalizeAll(account):
account_name = check_account(account)
password = ":".join(account.split(":")[1:])
if account_name == False:
return {
"error": {
"message": "Invalid account"
}
}
return sendBatch(account,[["FINALIZE"]])
def rescan_auction(account,domain):
# Get height of the start of the auction
response = hsw.rpc_selectWallet(account)
@ -981,99 +579,6 @@ def revoke(account,domain):
}
}
def sendBatch(account, batch):
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 = requests.post(f"http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}",json={
"method": "sendbatch",
"params": [batch]
}).json()
if response['error'] is not None:
return response
if 'result' not in response:
return {
"error": {
"message": "No result"
}
}
return response['result']
except Exception as e:
return {
"error": {
"message": str(e)
}
}
def createBatch(account, batch):
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 = requests.post(f"http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}",json={
"method": "createbatch",
"params": [batch]
}).json()
if response['error'] is not None:
return response
if 'result' not in response:
return {
"error": {
"message": "No result"
}
}
return response['result']
except Exception as e:
return {
"error": {
"message": str(e)
}
}
#region settingsAPIs
@ -1114,7 +619,7 @@ def zapTXs(account):
}
try:
response = requests.post(f"http://x:{HSD_API}@{HSD_IP}:{HSD_WALLET_PORT}/wallet/{account_name}/zap",
response = requests.post(f"http://x:{APIKEY}@{ip}:12039/wallet/{account_name}/zap",
json={"age": age,
"account": "default"
})
@ -1158,61 +663,6 @@ def getxPub(account):
}
def signMessage(account,domain,message):
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_signMessageWithName(domain,message)
return response
except Exception as e:
return {
"error": {
"message": str(e)
}
}
def verifyMessageWithName(domain,signature,message):
try:
response = hsd.rpc_verifyMessageWithName(domain,signature,message)
if 'result' in response:
return response['result']
return False
except Exception as e:
return False
def verifyMessage(address,signature,message):
try:
response = hsd.rpc_verifyMessage(address,signature,message)
if 'result' in response:
return response['result']
return False
except Exception as e:
return False
#endregion
def generateReport(account,format="{name},{expiry},{value},{maxBid}"):

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

View File

@ -9,9 +9,6 @@ import dns.asyncresolver
import httpx
from requests_doh import DNSOverHTTPSSession, add_dns_provider
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Disable insecure request warnings (since we are manually verifying the certificate)
def hip2(domain: str):
domain_check = False
@ -78,9 +75,9 @@ def hip2(domain: str):
break
expiry_date = cert_obj.not_valid_after_utc
expiry_date = cert_obj.not_valid_after
# Check if expiry date is past
if expiry_date < datetime.datetime.now(datetime.timezone.utc):
if expiry_date < datetime.datetime.now():
return "Hip2: Certificate is expired"
@ -117,7 +114,6 @@ def hip2(domain: str):
# Catch all exceptions
except Exception as e:
print(f"Hip2: Lookup failed with error: {e}",flush=True)
return "Hip2: Lookup failed."
@ -172,10 +168,4 @@ def emoji_to_punycode(emoji):
try:
return emoji.encode("idna").decode("ascii")
except Exception as e:
return emoji
def punycode_to_emoji(punycode):
try:
return punycode.encode("ascii").decode("idna")
except Exception as e:
return punycode
return ""

View File

@ -1,5 +1,3 @@
HSD_API=123480615465636893475aCwyaae6s45
HSD_IP=localhost
THEME=black
SHOW_EXPIRED=false
EXPLORER_TX=https://niami.io/tx/
hsd_api=123480615465636893475aCwyaae6s45
hsd_ip=localhost
theme=black

735
main.py

File diff suppressed because it is too large Load Diff

174
plugin.py
View File

@ -1,183 +1,46 @@
import os
import json
import importlib
import sys
import hashlib
import subprocess
def import_module(module_name):
if module_name in sys.modules:
return importlib.reload(sys.modules[module_name])
else:
return importlib.import_module(module_name)
def listPlugins(update=False):
def listPlugins():
plugins = []
for file in os.listdir("plugins"):
if file.endswith(".py"):
if file != "main.py":
plugin = import_module("plugins."+file[:-3])
if "info" not in dir(plugin):
continue
plugin = importlib.import_module("plugins."+file[:-3])
details = plugin.info
details["source"] = "built-in"
details["link"] = f"plugins/{file[:-3]}"
details["link"] = file[:-3]
plugins.append(details)
# Check for imported plugins
if not os.path.exists("user_data/plugins.json"):
with open("user_data/plugins.json", "w") as f:
json.dump([], f)
with open("user_data/plugins.json", "r") as f:
importurls = json.load(f)
for importurl in importurls:
# Get only repo name
importPath = importurl.split("/")[-1].removesuffix(".git")
# Git clone into customPlugins/<importPath>
if not os.path.exists(f"customPlugins/{importPath}"):
if os.system(f"git clone {importurl} customPlugins/{importPath}") != 0:
continue
elif update:
os.system(f"cd customPlugins/{importPath} && git pull")
# Import plugins from customPlugins/<importPath>
for file in os.listdir(f"customPlugins/{importPath}"):
if file.endswith(".py"):
if file != "main.py":
plugin = import_module(f"customPlugins.{importPath}."+file[:-3])
if "info" not in dir(plugin):
continue
details = plugin.info
details["source"] = importPath
details["link"] = f"customPlugins/{importPath}/{file[:-3]}"
plugins.append(details)
# Verify plugin signature
signatures = []
try:
with open("user_data/plugin_signatures.json", "r") as f:
signatures = json.load(f)
except:
# Write a new signatures file
with open("user_data/plugin_signatures.json", "w") as f:
json.dump(signatures, f)
for plugin in plugins:
# Hash the plugin file
pluginHash = hashPlugin(plugin["link"])
if pluginHash not in signatures:
plugin["verified"] = False
else:
plugin["verified"] = True
return plugins
def pluginExists(plugin: str):
return os.path.exists(plugin+".py")
def verifyPlugin(plugin: str):
signatures = []
try:
with open("user_data/plugin_signatures.json", "r") as f:
signatures = json.load(f)
except:
# Write a new signatures file
with open("user_data/plugin_signatures.json", "w") as f:
json.dump(signatures, f)
# Hash the plugin file
pluginHash = hashPlugin(plugin)
if pluginHash not in signatures:
signatures.append(pluginHash)
with open("user_data/plugin_signatures.json", "w") as f:
json.dump(signatures, f)
def hashPlugin(plugin: str):
BUF_SIZE = 65536
sha256 = hashlib.sha256()
with open(plugin+".py", 'rb') as f:
while True:
data = f.read(BUF_SIZE)
if not data:
break
sha256.update(data)
return sha256.hexdigest()
def getPluginData(pluginStr: str):
plugin = import_module(pluginStr.replace("/","."))
# Check if the plugin is verified
signatures = []
try:
with open("user_data/plugin_signatures.json", "r") as f:
signatures = json.load(f)
except:
# Write a new signatures file
with open("user_data/plugin_signatures.json", "w") as f:
json.dump(signatures, f)
info = plugin.info
info["source"] = "built-in"
# Check if the plugin is in customPlugins
if pluginStr.startswith("customPlugins"):
# Get git url for dir
url = subprocess.check_output(f"cd customPlugins/{pluginStr.split('/')[-2]} && git remote get-url origin", shell=True).decode("utf-8").strip()
info["source"] = url
# Hash the plugin file
pluginHash = hashPlugin(pluginStr)
if pluginHash not in signatures:
info["verified"] = False
else:
info["verified"] = True
return info
for file in os.listdir("plugins"):
if file == plugin+".py":
return True
return False
def getPluginData(plugin: str):
plugin = importlib.import_module("plugins."+plugin)
return plugin.info
def getPluginFunctions(plugin: str):
plugin = import_module(plugin.replace("/","."))
plugin = importlib.import_module("plugins."+plugin)
return plugin.functions
def runPluginFunction(plugin: str, function: str, params: dict, authentication: str):
plugin_module = import_module(plugin.replace("/","."))
plugin_module = importlib.import_module("plugins."+plugin)
if function not in plugin_module.functions:
return {"error": "Function not found"}
if not hasattr(plugin_module, function):
return {"error": "Function not found"}
# Get the function object from the plugin module
plugin_function = getattr(plugin_module, function)
# Check if the function is in the signature list
signatures = []
try:
with open("user_data/plugin_signatures.json", "r") as f:
signatures = json.load(f)
except:
# Write a new signatures file
with open("user_data/plugin_signatures.json", "w") as f:
json.dump(signatures, f)
# Hash the plugin file
pluginHash = hashPlugin(plugin)
if pluginHash not in signatures:
return {"error": "Plugin not verified"}
# Call the function with provided parameters
try:
result = plugin_function(params, authentication)
@ -187,17 +50,14 @@ def runPluginFunction(plugin: str, function: str, params: dict, authentication:
return {"error": str(e)}
# return plugin.runFunction(function, params, authentication)
def getPluginFunctionInputs(plugin: str, function: str):
plugin = import_module(plugin.replace("/","."))
plugin = importlib.import_module("plugins."+plugin)
return plugin.functions[function]["params"]
def getPluginFunctionReturns(plugin: str, function: str):
plugin = import_module(plugin.replace("/","."))
plugin = importlib.import_module("plugins."+plugin)
return plugin.functions[function]["returns"]
def getDomainFunctions():
plugins = listPlugins()
domainFunctions = []
@ -212,7 +72,6 @@ def getDomainFunctions():
})
return domainFunctions
def getSearchFunctions():
plugins = listPlugins()
searchFunctions = []
@ -227,7 +86,6 @@ def getSearchFunctions():
})
return searchFunctions
def getDashboardFunctions():
plugins = listPlugins()
dashboardFunctions = []
@ -240,4 +98,4 @@ def getDashboardFunctions():
"function": function,
"description": functions[function]["description"]
})
return dashboardFunctions
return dashboardFunctions

View File

@ -1,53 +1,5 @@
# Plugins
Plugins can be created to add more functionality to FireWallet Browser
## Format
They are created in python and use the format:
```python
info = {
"name": "Plugin Name",
"description": "Plugin Description",
"version": "Version number",
"author": "Your Name",
}
functions = {
"internalName":{
"name": "Human readable name",
"type": "Type of plugin",
"description": "Function description",
"params": { # For plugins other than default use {} for no params
"paramName": {
"name":"Human readable paramiter name",
"type":"type of paramiter",
}
},
"returns": {
"returnName":
{
"name": "Human readable return name",
"type": "type of return"
}
}
}
}
def internalName(params, authentication): # This should always have the same inputs
paramName = params["paramName"]
wallet = authentication.split(":")[0]
# Do stuff
output = "Return value of stuff: " + paramName
return {"returnName": output}
```
## Types
### Default
Type: `default`
@ -63,7 +15,6 @@ This type is used for domain plugins. It shows in the manage domain page or the
It gets the `domain` paramater as the only input (in addition to authentication)
### Dashboard
Type: `dashboard`
This type is used for dashboard plugins.
It shows in the dashboard page. It doesn't get any inputs other than the authentication

View File

@ -1,158 +0,0 @@
import json
import account
import requests
import threading
import os
import time
KEY = account.HSD_API
IP = account.HSD_IP
PORT = account.HSD_WALLET_PORT
if not os.path.exists("user_data"):
os.mkdir("user_data")
# Plugin Data
info = {
"name": "Automations",
"description": "This plugin will automatically renew domains, reveal and redeem bids.",
"version": "1.0",
"author": "Nathan.Woodburn/"
}
# Functions
functions = {
"automation":{
"name": "Function to automate",
"type": "dashboard",
"description": "This used type dashboard to trigger the function whenever you access the dashboard.",
"params": {},
"returns": {
"Status":
{
"name": "Status of the automation",
"type": "text"
}
}
},
"disable":{
"name": "Disable Automations",
"type": "default",
"description": "Disable Automations for this wallet",
"params": {},
"returns": {
"Status":
{
"name": "Status",
"type": "text"
}
}
},
"enable":{
"name": "Enable Automations",
"type": "default",
"description": "Enable Automations for this wallet",
"params": {},
"returns": {
"Status":
{
"name": "Status",
"type": "text"
}
}
},
"list":{
"name": "List Disabled Wallets",
"type": "default",
"description": "List wallets with automations disabled",
"params": {},
"returns": {
"wallets":
{
"name": "List of wallets",
"type": "list"
}
}
}
}
started = False
# Main entry point only lets the main function run every 5 mins
def automation(params, authentication):
global started
wallet = authentication.split(":")[0]
if os.path.exists(f"user_data/{wallet}.autoRenew"):
return {"Status": "Automations disabled"}
if started:
return {"Status": "Automations running"}
started = True
threading.Thread(target=automations_background, args=(authentication,)).start()
return {"Status": "Starting Automations..."}
def disable(params, authentication):
# Create walletname file in user_data
wallet = authentication.split(":")[0]
if not os.path.exists("user_data"):
os.mkdir("user_data")
with open(f"user_data/{wallet}.autoRenew", "w") as f:
f.write(f"This file is used to disable automations for '{wallet}' wallet.\nDelete this file to enable automations.")
return {"Status": "Disabled Automations"}
def enable(params, authentication):
# Delete walletname file in user_data
wallet = authentication.split(":")[0]
if os.path.exists(f"user_data/{wallet}.autoRenew"):
os.remove(f"user_data/{wallet}.autoRenew")
return {"Status": "Enabled Automations"}
def list(params, authentication):
wallets = []
for file in os.listdir("user_data"):
if file.endswith(".autoRenew"):
wallets.append(file[:-10])
return {"wallets": wallets}
# Background function to run the automations
def automations_background(authentication):
while True:
# Get account details
account_name = account.check_account(authentication)
password = ":".join(authentication.split(":")[1:])
if account_name == False:
return {
"error": {
"message": "Invalid account"
}
}
if os.path.exists(f"user_data/{account_name}.autoRenew"):
print("Skipping Automations")
time.sleep(300)
continue
print("Running automations")
try:
# Try to select and login to the wallet
response = account.hsw.rpc_selectWallet(account_name)
if response['error'] is not None:
return
response = account.hsw.rpc_walletPassphrase(password,30)
if response['error'] is not None:
return
# Try to send the batch of all renew, reveal and redeem actions
requests.post(f"http://x:{KEY}@{IP}:{PORT}",json={"method": "sendbatch","params": [[["RENEW"]]]})
requests.post(f"http://x:{KEY}@{IP}:{PORT}",json={"method": "sendbatch","params": [[["REVEAL"]]]})
requests.post(f"http://x:{KEY}@{IP}:{PORT}",json={"method": "sendbatch","params": [[["REDEEM"]]]})
except Exception as e:
print(e)
# Sleep for 5 mins before running again
time.sleep(300)

View File

@ -1,517 +0,0 @@
import json
import account
import requests
import os
# Plugin Data
info = {
"name": "Batching Functions",
"description": "This is a plugin that provides multiple functions to batch transactions",
"version": "1.0",
"author": "Nathan.Woodburn/"
}
# https://hsd-dev.org/api-docs/?shell--cli#sendbatch
# Functions
functions = {
"transfer":{
"name": "Batch transfer",
"type": "default",
"description": "Transfer a ton of domains",
"params": {
"domains": {
"name":"List of domains to transfer (one per line)",
"type":"longText"
},
"address": {
"name":"Address to transfer to",
"type":"address"
}
},
"returns": {
"status":
{
"name": "Status",
"type": "text"
},
"transaction":
{
"name": "Hash of the transaction",
"type": "tx"
}
}
},
"finalize":{
"name": "Batch finalize a transfer",
"type": "default",
"description": "Finalize transferring a ton of domains",
"params": {
"domains": {
"name":"List of domains to finalize (one per line)",
"type":"longText"
}
},
"returns": {
"status":
{
"name": "Status",
"type": "text"
},
"transaction":
{
"name": "Hash of the transaction",
"type": "tx"
}
}
},
"cancel":{
"name": "Batch cancel a transfer",
"type": "default",
"description": "Cancel transferring a ton of domains",
"params": {
"domains": {
"name":"List of domains to cancel (one per line)",
"type":"longText"
}
},
"returns": {
"status":
{
"name": "Status",
"type": "text"
},
"transaction":
{
"name": "Hash of the transaction",
"type": "tx"
}
}
},
"open":{
"name": "Batch open auctions",
"type": "default",
"description": "Open auctions for a ton of domains",
"params": {
"domains": {
"name":"List of domains to open (one per line)",
"type":"longText"
}
},
"returns": {
"status":
{
"name": "Status",
"type": "text"
},
"transaction":
{
"name": "Hash of the transaction",
"type": "tx"
}
}
},
"bid":{
"name": "Batch bid on auctions",
"type": "default",
"description": "Bid on auctions for a ton of domains",
"params": {
"domains": {
"name":"List of domains to bid on (one per line)",
"type":"longText"
},
"bid": {
"name":"Bid amount",
"type":"text"
},
"blind": {
"name":"Blind amount",
"type":"text"
}
},
"returns": {
"status":
{
"name": "Status",
"type": "text"
},
"transaction":
{
"name": "Hash of the transaction",
"type": "tx"
}
}
},
"reveal":{
"name": "Batch reveal bids",
"type": "default",
"description": "Reveal bids for tons of auctions",
"params": {
"domains": {
"name":"List of domains to reveal (one per line)",
"type":"longText"
}
},
"returns": {
"status":
{
"name": "Status",
"type": "text"
},
"transaction":
{
"name": "Hash of the transaction",
"type": "tx"
}
}
},
"redeem":{
"name": "Batch redeem bids",
"type": "default",
"description": "Redeem lost bids to get funds back",
"params": {
"domains": {
"name":"List of domains to redeem (one per line)",
"type":"longText"
}
},
"returns": {
"status":
{
"name": "Status",
"type": "text"
},
"transaction":
{
"name": "Hash of the transaction",
"type": "tx"
}
}
},
"register":{
"name": "Batch register domains",
"type": "default",
"description": "Register domains won in auction",
"params": {
"domains": {
"name":"List of domains to redeem (one per line)",
"type":"longText"
}
},
"returns": {
"status":
{
"name": "Status",
"type": "text"
},
"transaction":
{
"name": "Hash of the transaction",
"type": "tx"
}
}
},
"renew":{
"name": "Batch renew domains",
"type": "default",
"description": "Renew a ton of domain",
"params": {
"domains": {
"name": "Domains to renew (one per line)",
"type": "longText"
}
},
"returns": {
"status": {
"name": "Status",
"type": "text"
},
"transaction":
{
"name": "Hash of the transaction",
"type": "tx"
}
}
},
"advancedBid":{
"name": "Bid on domains with csv",
"type": "default",
"description": "Bid on domains using a csv format",
"params": {
"bids": {
"name":"List of bids in format `domain,bid,blind` (one per line)",
"type":"longText"
}
},
"returns": {
"status":
{
"name": "Status",
"type": "text"
},
"transaction":
{
"name": "Hash of the transaction",
"type": "tx"
}
}
},
"advancedBatch":{
"name": "Batch transactions with csv",
"type": "default",
"description": "Batch transactions using a csv format",
"params": {
"transactions": {
"name":"List of transactions in format `type,domain,param1,param2` (one per line) Eg.<br>TRANSFER,woodburn1,hs1q4rkfe5df7ss6wzhnw388hv27we0hp7ha2np0hk<br>OPEN,woodburn2",
"type":"longText"
}
},
"returns": {
"status":
{
"name": "Status",
"type": "text"
},
"transaction":
{
"name": "Hash of the transaction",
"type": "tx"
}
}
},
"advancedChangeLookahead":{
"name": "Change wallet lookahead",
"type": "default",
"description": "Change the lookahead of the wallet",
"params": {
"lookahead": {
"name":"Lookahead (default 200)",
"type":"number"
}
},
"returns": {
"status":
{
"name": "Status",
"type": "text"
}
}
}
}
def sendBatch(batch, authentication):
response = account.sendBatch(authentication, batch)
return response
def transfer(params, authentication):
domains = params["domains"]
address = params["address"]
domains = domains.splitlines()
domains = [x.strip() for x in domains]
domains = [x for x in domains if x != ""]
wallet = authentication.split(":")[0]
owned = account.getDomains(wallet)
# Only keep owned domains ["name"]
ownedNames = [domain["name"] for domain in owned]
for domain in domains:
if domain not in ownedNames:
return {
"status":f"Domain {domain} not owned",
"transaction":None
}
batch = []
for domain in domains:
batch.append(['TRANSFER', domain, address])
response = sendBatch(batch, authentication)
if 'error' in response:
return {
"status":response['error']['message'],
"transaction":None
}
return {
"status":"Sent batch successfully",
"transaction":response['hash']
}
def simple(batchType,params, authentication):
domains = params["domains"]
domains = domains.splitlines()
domains = [x.strip() for x in domains]
domains = [x for x in domains if x != ""]
batch = []
for domain in domains:
batch.append([batchType, domain])
print(batch)
response = sendBatch(batch, authentication)
if 'error' in response:
print(response)
return {
"status":response['error']['message'],
"transaction":None
}
return {
"status":"Sent batch successfully",
"transaction":response['hash']
}
def finalize(params, authentication):
return simple("FINALIZE",params,authentication)
def cancel(params, authentication):
return simple("CANCEL",params,authentication)
def open(params, authentication):
return simple("OPEN",params,authentication)
def bid(params, authentication):
domains = params["domains"]
domains = domains.splitlines()
domains = [x.strip() for x in domains]
domains = [x for x in domains if x != ""]
try:
bid = float(params["bid"])
blind = float(params["blind"])
blind+=bid
except:
return {
"status":"Invalid bid amount",
"transaction":None
}
batch = []
for domain in domains:
batch.append(['BID', domain, bid, blind])
print(batch)
response = sendBatch(batch, authentication)
if 'error' in response:
return {
"status":response['error']['message'],
"transaction":None
}
return {
"status":"Sent batch successfully",
"transaction":response['hash']
}
def reveal(params, authentication):
return simple("REVEAL",params,authentication)
def redeem(params, authentication):
return simple("REDEEM",params,authentication)
def register(params, authentication):
domains = params["domains"]
domains = domains.splitlines()
domains = [x.strip() for x in domains]
domains = [x for x in domains if x != ""]
batch = []
for domain in domains:
batch.append(['UPDATE', domain,{"records": []}])
print(batch)
response = sendBatch(batch, authentication)
if 'error' in response:
return {
"status":response['error']['message'],
"transaction":None
}
return {
"status":"Sent batch successfully",
"transaction":response['hash']
}
def renew(params, authentication):
return simple("RENEW", params, authentication)
def advancedBid(params, authentication):
bids = params["bids"]
bids = bids.splitlines()
bids = [x.strip() for x in bids]
bids = [x for x in bids if x != ""]
batch = []
for bid in bids:
# Split the bid
line = bid.split(",")
domain = line[0]
bid = float(line[1])
blind = float(line[2])
blind+=bid
batch.append(['BID', domain, bid, blind])
print(batch)
response = sendBatch(batch, authentication)
if 'error' in response:
return {
"status":response['error']['message'],
"transaction":None
}
return {
"status":"Sent batch successfully",
"transaction":response['hash']
}
def advancedBatch(params, authentication):
transactions = params["transactions"]
transactions = transactions.splitlines()
transactions = [x.strip() for x in transactions]
transactions = [x for x in transactions if x != ""]
batch = []
for transaction in transactions:
# Split the bid
line = transaction.split(",")
line[0] = line[0].upper()
batch.append(line)
print(batch)
response = sendBatch(batch, authentication)
if 'error' in response:
return {
"status":response['error']['message'],
"transaction":None
}
return {
"status":"Sent batch successfully",
"transaction":response['hash']
}
def advancedChangeLookahead(params, authentication):
lookahead = params["lookahead"]
lookahead = int(lookahead)
wallet = authentication.split(":")[0]
password = ":".join(authentication.split(":")[1:])
KEY = account.HSD_API
IP = account.HSD_IP
PORT = account.HSD_WALLET_PORT
# Unlock wallet
response = requests.post(f"http://x:{KEY}@{IP}:{PORT}/wallet/{wallet}/unlock",
json={"passphrase": password, "timeout": 10})
response = requests.patch(f"http://x:{KEY}@{IP}:{PORT}/wallet/{wallet}/account/default",
json={"lookahead": lookahead})
return {
"status":f"Status: {'Success' if response.status_code == 200 else 'Error'}"
}

View File

@ -1,114 +0,0 @@
import json
import account
import requests
import os
# Plugin Data
info = {
"name": "Custom Plugin Manager",
"description": "Import custom plugins from git repositories<br>Find some plugins <a href=https://git.woodburn.au/nathanwoodburn?tab=repositories&q=plugin&sort=recentupdate target=_blank>here</a>",
"version": "1.0",
"author": "Nathan.Woodburn/"
}
# Functions
functions = {
"add":{
"name": "Add Plugin repo",
"type": "default",
"description": "Add a plugin repo",
"params": {
"url": {
"name":"URL",
"type":"text"
}
},
"returns": {
"status":
{
"name": "Status of the function",
"type": "text"
}
}
},
"remove":{
"name": "Remove Plugins",
"type": "default",
"description": "Remove a plugin repo from the list",
"params": {
"url": {
"name":"URL",
"type":"text"
}
},
"returns": {
"status":
{
"name": "Status of the function",
"type": "text"
}
}
},
"list":{
"name": "List Plugins",
"type": "default",
"description": "List all imported plugins",
"params": {},
"returns": {
"plugins":
{
"name": "List of plugins",
"type": "list"
}
}
}
}
def add(params, authentication):
url = params["url"]
if not os.path.exists("user_data/plugins.json"):
with open("user_data/plugins.json", "w") as f:
json.dump([], f)
with open("user_data/plugins.json", "r") as f:
importurls = json.load(f)
# Check if the plugin is already imported
if url in importurls:
return {"status": "Plugin already imported"}
importurls.append(url)
with open("user_data/plugins.json", "w") as f:
json.dump(importurls, f)
return {"status": "Imported"}
def remove(params, authentication):
url = params["url"]
if not os.path.exists("user_data/plugins.json"):
with open("user_data/plugins.json", "w") as f:
json.dump([], f)
with open("user_data/plugins.json", "r") as f:
importurls = json.load(f)
# Check if the plugin is already imported
if url not in importurls:
return {"status": "Plugin not imported"}
importurls.remove(url)
with open("user_data/plugins.json", "w") as f:
json.dump(importurls, f)
return {"status": "Removed"}
def list(params, authentication):
if not os.path.exists("user_data/plugins.json"):
with open("user_data/plugins.json", "w") as f:
json.dump([], f)
with open("user_data/plugins.json", "r") as f:
importurls = json.load(f)
return {"plugins": importurls}

175
plugins/example.py Normal file
View File

@ -0,0 +1,175 @@
import json
import account
import requests
# Plugin Data
info = {
"name": "Example Plugin",
"description": "This is a plugin to be used as an example",
"version": "1.0",
"author": "Nathan.Woodburn/"
}
# Functions
functions = {
"search":{
"name": "Search Owned",
"type": "default",
"description": "Search for owned domains containing a string",
"params": {
"search": {
"name":"Search string",
"type":"text"
}
},
"returns": {
"domains":
{
"name": "List of owned domains",
"type": "list"
}
}
},
"transfer":{
"name": "Bulk Transfer Domains",
"type": "default",
"description": "Transfer domains to another wallet",
"params": {
"address": {
"name":"Address to transfer to",
"type":"address"
},
"domains": {
"name":"List of domains to transfer",
"type":"longText"
}
},
"returns": {
"hash": {
"name": "Hash of the transaction",
"type": "tx"
},
"address":{
"name": "Address of the new owner",
"type": "text"
}
}
},
"dns":{
"name": "Set DNS for Domains",
"type": "default",
"description": "Set DNS for domains",
"params": {
"domains": {
"name":"List of domains to set DNS for",
"type":"longText"
},
"dns": {
"name":"DNS",
"type":"dns"
}
},
"returns": {
"hash": {
"name": "Hash of the transaction",
"type": "tx"
},
"dns":{
"name": "DNS",
"type": "dns"
}
}
},
"niami": {
"name": "Niami info",
"type": "domain",
"description": "Check the domains niami rating",
"params": {},
"returns": {
"rating":
{
"name": "Niami Rating",
"type": "text"
}
}
},
"niamiSearch": {
"name": "Niami info",
"type": "search",
"description": "Check the domains niami rating",
"params": {},
"returns": {
"rating":
{
"name": "Niami Rating",
"type": "text"
}
}
},
"connections":{
"name": "HSD Connections",
"type": "dashboard",
"description": "Show the number of connections the HSD node is connected to",
"params": {},
"returns": {
"connections":
{
"name": "HSD Connections",
"type": "text"
}
}
}
}
def check(params, authentication):
domains = params["domains"]
domains = domains.splitlines()
wallet = authentication.split(":")[0]
owned = account.getDomains(wallet)
# Only keep owned domains ["name"]
ownedNames = [domain["name"] for domain in owned]
domains = [domain for domain in domains if domain in ownedNames]
return {"domains": domains}
def search(params, authentication):
search = params["search"]
wallet = authentication.split(":")[0]
owned = account.getDomains(wallet)
# Only keep owned domains ["name"]
ownedNames = [domain["name"] for domain in owned]
domains = [domain for domain in ownedNames if search in domain]
return {"domains": domains}
def transfer(params, authentication):
address = params["address"]
return {"hash":"f921ffe1bb01884bf515a8079073ee9381cb93a56b486694eda2cce0719f27c0","address":address}
def dns(params,authentication):
dns = params["dns"]
return {"hash":"f921ffe1bb01884bf515a8079073ee9381cb93a56b486694eda2cce0719f27c0","dns":dns}
def niami(params, authentication):
domain = params["domain"]
print(domain)
response = requests.get(f"https://api.handshake.niami.io/domain/{domain}")
print(response.text)
data = response.json()["data"]
rating = str(data["rating"]["score"]) + " (" + data["rating"]["rarity"] + ")"
return {"rating":rating}
def niamiSearch(params, authentication):
return niami(params, authentication)
def connections(params,authentication):
outbound = account.hsd.getInfo()['pool']['outbound']
return {"connections": outbound}

View File

@ -1,97 +0,0 @@
import json
import account
import requests
import os
# Plugin Data
info = {
"name": "Batch Renew Domains",
"description": "Renew the next 100 domains",
"version": "1.0",
"author": "Nathan.Woodburn/"
}
# Functions
functions = {
"main":{
"name": "Renew",
"type": "default",
"description": "Renew the next 100 domains in one transaction. Please wait for at least 1 block confirmation before renewing the next 100 domains",
"params": {},
"returns": {
"status":
{
"name": "Status of the function",
"type": "text"
},
"transaction":
{
"name": "Transaction ID",
"type": "tx"
}
}
}
}
def main(params, authentication):
password = authentication.split(":")[1]
wallet = authentication.split(":")[0]
domains = account.getDomains(wallet)
domains = sorted(domains, key=lambda k: k['renewal'])
names = []
for domain in domains:
name = domain["name"]
names.append(name)
# Split names into batches of 100
batches = []
for i in range(0, len(names), 100):
batches.append(names[i:i+100])
# Unlock wallet
KEY = account.HSD_API
IP = account.HSD_IP
PORT = account.HSD_WALLET_PORT
response = requests.post(f'http://x:{KEY}@{IP}:{PORT}/wallet/{wallet}/unlock',
json={'passphrase': password, 'timeout': 600})
if response.status_code != 200:
print("Failed to unlock wallet")
print(f'Status code: {response.status_code}')
print(f'Response: {response.text}')
return {"status": "Failed unlocking wallet", "transaction": "None"}
tx = "None"
for batch in batches:
batch = []
for domain in names:
batch.append(f'["RENEW", "{domain}"]')
batchTX = "[" + ", ".join(batch) + "]"
responseContent = f'{{"method": "sendbatch","params":[ {batchTX} ]}}'
response = requests.post(f'http://x:{KEY}@{IP}:{PORT}', data=responseContent)
if response.status_code != 200:
print("Failed to create batch",flush=True)
print(f'Status code: {response.status_code}',flush=True)
print(f'Response: {response.text}',flush=True)
return {"status": "Failed", "transaction": "None"}
batch = response.json()
# Verify the batch
print("Verifying tx...")
if batch["error"]:
if batch["error"] != "":
print("Failed to verify batch",flush=True)
print(batch["error"]["message"],flush=True)
return {"status": f"Failed: {batch['error']['message']}", "transaction": "None"}
if 'result' in batch:
if batch['result'] != None:
tx = batch['result']['hash']
return {"status": "Success", "transaction": tx}
# Note only one batch can be sent at a time

View File

@ -1,195 +0,0 @@
import json
import account
import requests
import os
if not os.path.exists("user_data"):
os.mkdir("user_data")
# Plugin Data
info = {
"name": "Varo Functions",
"description": "Integration with Varo.",
"version": "1.0",
"author": "Nathan.Woodburn/"
}
# Functions
functions = {
"status":{
"name": "Check connection",
"type": "dashboard",
"description": "You need to login to the varo instance before you can use this function.",
"params": {},
"returns": {
"status":
{
"name": "Status of varo connection",
"type": "text"
}
}
},
"login":{
"name": "Login to Varo",
"type": "default",
"description": "Login to Varo<br>Use the domain of the varo instance (eg. <a target='_blank' href='https://domains.hns.au'>domains.hns.au</a>) and API key from the dashboard.",
"params": {
"instance": {
"name":"Varo instance",
"type":"text"
},
"api": {
"name":"API key",
"type":"text"
}
},
"returns": {
"status":
{
"name": "Status of the function",
"type": "text"
}
}
},
"addDomain":{
"name": "Add domain",
"type": "default",
"description": "Add a domain to Varo",
"params": {
"domain": {
"name":"Domain",
"type":"text"
}
},
"returns": {
"status":
{
"name": "Status of the function",
"type": "text"
}
}
}
}
def status(params, authentication):
# Try to connect to Varo
if not os.path.exists("user_data/varo.json"):
return {"status": "Missing Varo API or instance"}
with open("user_data/varo.json", "r") as f:
auth = json.load(f)
if not auth:
return {"status": "Missing Varo API or instance"}
if 'api' not in auth or 'instance' not in auth:
return {"status": "Missing Varo API or instance"}
api = auth["api"]
instance = auth["instance"]
headers = {"Authorization": f"Bearer {api}"}
data = {
"action": "getInfo"
}
response = requests.post(f"https://{instance}/api", json=data, headers=headers)
if response.status_code != 200:
return {"status": "Error connecting to Varo"}
if response.json()["success"] != True:
return {"status": "Error connecting to Varo"}
return {"status": f"Connected to {instance}"}
def login(params, authentication):
# Verify the user has entered the correct details
instance = params["instance"]
api = params["api"]
# Strip the https:// from the instance
instance = instance.replace("https://", "")
instance = instance.replace("http://", "")
response = requests.post(f"https://{instance}/api", json={"action": "getInfo"}, headers={"Authorization": f"Bearer {api}"})
if response.status_code != 200:
return {"status": "Error connecting to Varo"}
if response.json()["success"] != True:
return {"status": "Error connecting to Varo"}
auth = {
"instance": instance,
"api": api
}
# Save the API key to the varo.json file
with open("user_data/varo.json", "w") as f:
json.dump(auth, f)
return {"status": "Success"}
def addDomain(params, authentication):
# Add a domain to Varo
domain = params["domain"]
if not os.path.exists("user_data/varo.json"):
return {"status": "Missing Varo API or instance"}
with open("user_data/varo.json", "r") as f:
auth = json.load(f)
if not auth:
return {"status": "Missing Varo API or instance"}
if 'api' not in auth or 'instance' not in auth:
return {"status": "Missing Varo API or instance"}
api = auth["api"]
instance = auth["instance"]
headers = {"Authorization": f"Bearer {api}"}
data = {
"action": "getZones"
}
zones = requests.post(f"https://{instance}/api", json=data, headers=headers)
if zones.status_code != 200:
return {"status": "Error connecting to Varo"}
if zones.json()["success"] != True:
return {"status": "Error connecting to Varo"}
zones = zones.json()["data"]
for zone in zones:
if zone["name"] == domain:
return {"status": "Domain already exists"}
# Check domain is owned by user
wallet = authentication.split(":")[0]
owned = account.getDomains(wallet)
# Only keep owned domains ["name"]
ownedNames = [domain["name"] for domain in owned]
if domain not in ownedNames:
return {"status": "Domain not owned by user"}
data = {
"action": "createZone",
"domain": domain
}
response = requests.post(f"https://{instance}/api", json=data, headers=headers)
if response.status_code != 200:
return {"status": "Error connecting to Varo"}
if response.json()["success"] != True:
return {"status": "Error connecting to Varo"}
zoneID = response.json()["data"]["zone"]
data = {
"action": "showZone",
"zone": zoneID
}
response = requests.post(f"https://{instance}/api", json=data, headers=headers)
if response.status_code != 200:
return {"status": "Error connecting to Varo"}
if response.json()["success"] != True:
return {"status": "Error connecting to Varo"}
zone = response.json()["data"]
dns = []
for ns in zone['NS']:
dns.append({'type': 'NS', 'value': ns})
ds = zone['DS']
ds = ds.split(' ')
dns.append({'type': 'DS', 'keyTag': int(ds[0]), 'algorithm': int(ds[1]), 'digestType': int(ds[2]), 'digest': ds[3]})
dns = json.dumps(dns)
response = account.setDNS(authentication,domain,dns)
return {"status": "Success"}

134
render.py
View File

@ -2,52 +2,32 @@ import datetime
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):
def domains(domains):
html = ''
for domain in domains:
owner = domain['owner']
if 'index' in owner:
if owner['index'] == 0:
continue
expires = domain['stats']
if 'daysUntilExpire' in expires:
expires = expires['daysUntilExpire']
else:
expires = "No expiration date"
paid = domain['value']
paid = paid / 1000000
# Handle punycodes
name = domain['name']
emoji = punycode_to_emoji(name)
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:,.2f} HNS</td><td><a href="{link}">{link_action}</a></td></tr>'
else:
html += f'<tr><td><a href="{link}">{name}</a></td><td>{expires} days</td></tr>'
html += f'<tr><td>{domain["name"]}</td><td>{expires} days</td><td>{paid} HNS</td><td><a href="/manage/{domain["name"]}">Manage</a></td></tr>'
return html
def transactions(txs):
if len(txs) == 0:
return '<tr><td colspan="5">No transactions found</td></tr>'
html = ''
# Reverse the list
txs = txs[::-1]
for tx in txs:
action = "HNS Transfer"
address = tx["outputs"][0]["address"]
@ -73,15 +53,22 @@ def transactions(txs):
amount += output["value"]
amount = amount / 1000000
amount = round(amount, 2)
amount = "{:,}".format(amount)
hash = f"<a target='_blank' href='{TX_EXPLORER_URL}{hash}'>{hash[:8]}...</a>"
hash = "<a target='_blank' href='https://niami.io/tx/" + hash + "'>" + hash[:8] + "...</a>"
if confirmations < 5:
confirmations = f"<td style='background-color: red;'>{confirmations}</td>"
confirmations = "<td style='background-color: red;'>" + str(confirmations) + "</td>"
else:
confirmations = f"<td>{confirmations:,}</td>"
confirmations = "<td>" + str(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
@ -105,14 +92,14 @@ def dns(data, edit=False):
elif entry['type'] == 'DS':
ds = f"{entry['keyTag']} {entry['algorithm']} {entry['digestType']} {entry['digest']}"
ds = str(entry['keyTag']) + " " + str(entry['algorithm']) + " " + str(entry['digestType']) + " " + entry['digest']
html_output += f"<td>{ds}</td>\n"
else:
value = ""
for key, val in entry.items():
if key != 'type':
value += f'{val} '
value += str(val) + " "
html_output += f"<td>{value}</td>\n"
if edit:
@ -132,16 +119,18 @@ def txs(data):
for entry in data:
html_output += f"<tr><td>{entry['action']}</td>\n"
html_output += f"<td><a target='_blank' href='{TX_EXPLORER_URL}{entry['txid']}'>{entry['txid'][:8]}...</a></td>\n"
html_output += f"<td><a target='_blank' href='https://niami.io/tx/{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:,.2f} HNS</td>\n"
html_output += f"<td>{amount} HNS</td>\n"
else:
blind = entry['blind']
blind = blind / 1000000
html_output += f"<td>{amount:,.2f} + {blind:,.2f} HNS</td>\n"
blind = round(blind, 2)
html_output += f"<td>{amount} + {blind} HNS</td>\n"
html_output += f"<td>{timestamp_to_readable_time(entry['time'])}</td>\n"
html_output += f"</tr>\n"
@ -160,17 +149,20 @@ def bids(bids,reveals):
for bid in bids:
lockup = bid['lockup']
lockup = lockup / 1000000
lockup = round(lockup, 2)
html += "<tr>"
html += f"<td>{lockup:,.2f} HNS</td>"
html += f"<td>{lockup} HNS</td>"
revealed = False
for reveal in reveals:
if reveal['bid'] == bid['prevout']['hash']:
revealed = True
value = reveal['value']
value = value / 1000000
html += f"<td>{value:,.2f} HNS</td>"
value = round(value, 2)
html += f"<td>{value} HNS</td>"
bidValue = lockup - value
html += f"<td>{bidValue:,.2f} HNS</td>"
bidValue = round(bidValue, 2)
html += f"<td>{bidValue} HNS</td>"
break
if not revealed:
html += f"<td>Hidden until reveal</td>"
@ -183,46 +175,6 @@ def bids(bids,reveals):
return html
def bidDomains(bids,domains, sortbyDomains=False):
html = ''
if not sortbyDomains:
for bid in bids:
for domain in domains:
if bid['name'] == domain['name']:
lockup = bid['lockup']
lockup = lockup / 1000000
bidValue = bid['value'] / 1000000
blind = lockup - bidValue
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 += "</tr>"
else:
for domain in domains:
for bid in bids:
if bid['name'] == domain['name']:
lockup = bid['lockup']
lockup = lockup / 1000000
bidValue = bid['value'] / 1000000
blind = lockup - bidValue
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 += "</tr>"
return html
def wallets(wallets):
html = ''
for wallet in wallets:
@ -235,10 +187,7 @@ def plugins(plugins):
name = plugin['name']
link = plugin['link']
if plugin['verified']:
html += f'<li class="list-group-item"><a class="btn btn-secondary" style="width:100%;height:100%;margin:0px;font-size: x-large;" role="button" href="/plugin/{link}">{name}</a></li>'
else:
html += f'<li class="list-group-item"><a class="btn btn-danger" style="width:100%;height:100%;margin:0px;font-size: x-large;" role="button" href="/plugin/{link}">{name} (Not verified)</a></li>'
html += f'<li class="list-group-item"><a class="btn btn-primary" style="width:100%;height:100%;margin:0px;font-size: x-large;" role="button" href="/plugin/{link}">{name}</a></li>'
return html
def plugin_functions(functions, pluginName):
@ -316,12 +265,11 @@ def plugin_output(outputs, returns):
html = ''
for returnOutput in returns:
if returnOutput not in outputs:
continue
html += f'<div class="card" style="margin-top: 50px; margin-bottom: 50px;">'
html += f'<div class="card-body">'
html += f'<h4 class="card-title">{returns[returnOutput]["name"]}</h4>'
# Get the output
output = outputs[returnOutput]
if returns[returnOutput]["type"] == "list":
html += f'<ul>'
@ -346,9 +294,9 @@ def plugin_output_dash(outputs, returns):
html = ''
for returnOutput in returns:
if returnOutput not in outputs:
continue
if outputs[returnOutput] == None:
continue
html += render_template('components/dashboard-plugin.html', name=returns[returnOutput]["name"], output=outputs[returnOutput])
html += render_template('components/dashboard-plugin.html', name=returns[returnOutput]["name"], output=outputs[returnOutput])
html += f'</div>'
html += f'</div>'
return html

View File

@ -7,5 +7,4 @@ dnspython
cryptography
requests-doh
Flask-QRcode
PySocks
python-git-info
PySocks

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -74,7 +72,7 @@
</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 2025</span></div>
<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>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 434 KiB

View File

@ -1 +0,0 @@
.fab.fa-bitcoin:before{content:"\f379"}.far.fa-calendar:before,.fas.fa-calendar:before{content:"\f133"}.far.fa-clipboard:before,.fas.fa-clipboard:before{content:"\f328"}.fab.fa-facebook-f:before{content:"\f39e"}.fab.fa-google-plus:before{content:"\f2b3"}.fas.fa-hotel:before{content:"\f594"}.fab.fa-linkedin:before{content:"\f08c"}.fas.fa-reply:before{content:"\f3e5"}.fas.fa-thermometer:before{content:"\f491"}.fab.fa-vimeo:before{content:"\f40a"}.far.fa-window-close:before,.fas.fa-window-close:before{content:"\f410"}.fab.fa-youtube-square:before{content:"\f431"}

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

Binary file not shown.

View File

@ -1 +0,0 @@
function createCard(e,n,t){if(document.getElementById(t)&&document.getElementById(t).remove(),n<=0)return;const a=document.createElement("div");a.classList.add("col-md-6","col-xl-3","mb-4"),a.id=t,html=`\n <div class="card shadow border-start-warning py-2">\n <div class="card-body">\n <div class="row align-items-center no-gutters">\n <div class="col me-2">\n <div class="text-uppercase text-warning fw-bold text-xs mb-1"><span>${e}</span></div>\n <div class="text-dark fw-bold h5 mb-0"><span id="${e}">${n}</span></div>\n </div>\n <div class="col"><a class="btn btn-primary" role="button" href="/all/${t.toLowerCase()}">${t} All</a></div>\n <div class="col-auto"><svg class="fa-2x text-gray-300" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="1em" viewBox="0 0 24 24" width="1em" fill="currentColor">\n <g>\n <rect fill="none" height="24" width="24"></rect>\n </g>\n <g>\n <path d="M12,2C6.48,2,2,6.48,2,12c0,5.52,4.48,10,10,10s10-4.48,10-10C22,6.48,17.52,2,12,2z M7,13.5c-0.83,0-1.5-0.67-1.5-1.5 c0-0.83,0.67-1.5,1.5-1.5s1.5,0.67,1.5,1.5C8.5,12.83,7.83,13.5,7,13.5z M12,13.5c-0.83,0-1.5-0.67-1.5-1.5 c0-0.83,0.67-1.5,1.5-1.5s1.5,0.67,1.5,1.5C13.5,12.83,12.83,13.5,12,13.5z M17,13.5c-0.83,0-1.5-0.67-1.5-1.5 c0-0.83,0.67-1.5,1.5-1.5s1.5,0.67,1.5,1.5C18.5,12.83,17.83,13.5,17,13.5z"></path>\n </g>\n </svg></div>\n </div>\n </div>`,a.innerHTML=html,document.getElementById("actions-row").appendChild(a)}async function updateActions(){const e={Finalize:"Pending Finalizes",Register:"Pending Register",Redeem:"Pending Redeem",Reveal:"Pending Reveal"};for(const n in e){const t=await request(`wallet/pending${n}`);"Error"!=t&&createCard(e[n],t.length,n)}}window.addEventListener("load",(async()=>{updateActions()})),setInterval((async function(){updateActions()}),2e4);

View File

@ -1 +1 @@
function copyToClipboard(){var e=document.getElementById("data");e.style.display="block",e.select(),e.setSelectionRange(0,99999),document.execCommand("copy"),e.style.display="none",document.getElementById("copyButton").innerHTML="Copied"}
function copyAddress(){var e=document.getElementById("copyLink").getAttribute("address"),t=document.createElement("input");t.value=e,document.body.appendChild(t),t.select(),t.setSelectionRange(0,99999),navigator.clipboard.writeText(t.value),document.body.removeChild(t),document.getElementById("copyLink").innerHTML="Copied!"}

View File

@ -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 n=await t.json();return void 0!==n.error?`Error: ${n.error}`:n.result}catch(e){return console.error("Request failed:",e),"Error"}}function sortTable(e,t=!1){const n=document.getElementById("data-table"),a=n.querySelector("tbody"),l=Array.from(a.querySelectorAll("tr")),r=n.querySelectorAll("th");let o=n.getAttribute("data-sort-order")||"asc",d=n.getAttribute("data-sort-column")||"-1";o=t||d!=e?"asc":"asc"===o?"desc":"asc",n.setAttribute("data-sort-order",o),n.setAttribute("data-sort-column",e),l.sort(((t,n)=>{let a=t.cells[e].innerText.trim(),l=n.cells[e].innerText.trim(),r=parseFloat(a.replace(/[^0-9.,]/g,"").replace(/,/g,"")),d=parseFloat(l.replace(/[^0-9.,]/g,"").replace(/,/g,""));return isNaN(r)||isNaN(d)?"asc"===o?a.localeCompare(l):l.localeCompare(a):"asc"===o?r-d:d-r})),a.innerHTML="",l.forEach((e=>a.appendChild(e))),updateSortIndicators(r,e,o)}function updateSortIndicators(e,t,n){e.forEach(((e,a)=>{let l=e.querySelector(".sort-indicator");l.innerHTML=a===t?"asc"===n?" ▲":" ▼":""}))}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"],n=["wallet-pendingReveal","wallet-pendingRegister","wallet-pendingRedeem"];for(const a of e){const e=document.getElementById(a);if(e){const l=a.replace(/-/g,"/");let r=await request(l);n.includes(a)&&"Error"!=r&&(r=r.length),t.includes(a)&&(r=Number(r).toFixed(2)),r=r.toString().replace(/\B(?=(\d{3})+(?!\d))/g,","),e.innerHTML=r}}})),document.addEventListener("DOMContentLoaded",(function(){fetch("/api/v1/wallet/domains").then((e=>e.json())).then((e=>{const t=document.querySelector("#data-table tbody");t&&(t.innerHTML="",e.result.forEach((e=>{const n=document.createElement("tr"),a=document.createElement("td");a.textContent=e.name,n.appendChild(a);var l="Unknown";"stats"in e&&"daysUntilExpire"in e.stats&&(l=e.stats.daysUntilExpire);const r=document.createElement("td");r.textContent=`${l} days`,n.appendChild(r);const o=document.createElement("td");o.textContent=`${(e.value/1e6).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g,",")} HNS`,n.appendChild(o);const d=document.createElement("td");d.innerHTML=e.registered?"<a href='/manage/"+e.name+"'>Manage</a>":"<a href='/auction/"+e.name+"/register'>Register</a>",n.appendChild(d),t.appendChild(n)})),sortTable(0,!0))})).catch((e=>console.error("Error fetching data:",e)))})),setInterval((async function(){const e=["hsd-sync","hsd-height","wallet-sync","wallet-pending","wallet-available","wallet-total"];for(const t of e){const e=document.getElementById(t);if(e){const n=t.replace(/-/g,"/");let a=await request(n);["wallet-available","wallet-total"].includes(t)&&(a=Number(a).toFixed(2)),a=a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,","),e.innerHTML=a}}}),2e4),function(){"use strict";var e=document.querySelector(".sidebar"),t=document.querySelectorAll("#sidebarToggle, #sidebarToggleTop");if(e){e.querySelector(".collapse");var n=[].slice.call(document.querySelectorAll(".sidebar .collapse")).map((function(e){return new bootstrap.Collapse(e,{toggle:!1})}));for(var a of t)a.addEventListener("click",(function(t){if(document.body.classList.toggle("sidebar-toggled"),e.classList.toggle("toggled"),e.classList.contains("toggled"))for(var a of n)a.hide()}));window.addEventListener("resize",(function(){if(Math.max(document.documentElement.clientWidth||0,window.innerWidth||0)<768)for(var e of n)e.hide()}))}var l=document.querySelector("body.fixed-nav .sidebar");l&&l.on("mousewheel DOMMouseScroll wheel",(function(e){if(Math.max(document.documentElement.clientWidth||0,window.innerWidth||0)>768){var t=e.originalEvent,n=t.wheelDelta||-t.detail;this.scrollTop+=30*(n<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"}))}();
!function(){"use strict";var e=document.querySelector(".sidebar"),o=document.querySelectorAll("#sidebarToggle, #sidebarToggleTop");if(e){e.querySelector(".collapse");var t=[].slice.call(document.querySelectorAll(".sidebar .collapse")).map((function(e){return new bootstrap.Collapse(e,{toggle:!1})}));for(var l of o)l.addEventListener("click",(function(o){if(document.body.classList.toggle("sidebar-toggled"),e.classList.toggle("toggled"),e.classList.contains("toggled"))for(var l of t)l.hide()}));window.addEventListener("resize",(function(){if(Math.max(document.documentElement.clientWidth||0,window.innerWidth||0)<768)for(var e of t)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 o=e.originalEvent,t=o.wheelDelta||-o.detail;this.scrollTop+=30*(t<0?1:-1),e.preventDefault()}}));var i=document.querySelector(".scroll-to-top");i&&window.addEventListener("scroll",(function(){var e=window.pageYOffset;i.style.display=e>100?"block":"none"}))}();

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -106,7 +104,7 @@
</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 2025</span></div>
<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>

View File

@ -1,210 +0,0 @@
<!DOCTYPE html>
<html data-bs-theme="dark" lang="en-au">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>Auctions - 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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" 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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</span></a></li>
</ul>
</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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></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>&nbsp;Logout</a></div>
</div>
</li>
</ul>
</div>
</nav>
<div class="container-fluid">
<div class="d-sm-flex justify-content-between align-items-center mb-4">
<h3 class="text-dark mb-0">Auctions</h3>
</div>
<h1 class="text-center">{{message}}</h1>
<div class="row">
<div class="col-md-6 col-xl-3 mb-4">
<div class="card shadow border-start-primary py-2">
<div class="card-body">
<div class="row align-items-center no-gutters">
<div class="col me-2">
<div class="text-uppercase text-primary fw-bold text-xs mb-1"><span style="color: var(--bs-dark);">HNS Locked</span></div>
<div class="text-dark fw-bold h5 mb-0"><span><img src="/assets/img/HNS.png" width="20px">&nbsp;<span id="wallet-locked">0.00</span></span></div>
</div>
<div class="col-auto"><i class="fas fa-dollar-sign fa-2x text-gray-300"></i></div>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-xl-3 mb-4">
<div class="card shadow border-start-success py-2">
<div class="card-body">
<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 id="wallet-bidCount">0</span></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 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 id="wallet-pendingReveal">0</span></div>
</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>
</div>
</div>
</div>{{plugins|safe}}
</div>
<div class="row d-none d-sm-none d-md-block">
<div class="col">
<div class="card shadow mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="text-primary fw-bold m-0">Domains</h6>
</div>
<div class="card-body"><div class="table-responsive">
<table class="table">
<thead>
<tr>
<th><a href="/auctions?sort=domain&direction={{sort_domain_next}}">Domain{{sort_domain}}</a></th>
<th><a href="/auctions?sort=state&direction={{sort_state_next}}">State{{sort_state}}</a></th>
<th><a href="/auctions?sort=price&direction={{sort_price_next}}">Bid{{sort_price}}</a></th>
<th><a href="/auctions?sort=time&direction={{sort_time_next}}">Block{{sort_time}}</a></th>
<th></th>
</tr>
</thead>
<tbody>
{{domains | safe}}
</tbody>
</table>
</div></div>
</div>
</div>
</div>
<div class="row d-block d-sm-block d-md-none">
<div class="col">
<div class="card shadow mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="text-primary fw-bold m-0">Domains</h6>
</div>
<div class="card-body"><div class="table-responsive">
<table class="table">
<thead>
<tr>
<th><a href="/auctions?direction={{sort_domain_next}}">Domain{{sort_domain}}</a></th>
<th><a href="/auctions?sort=state&direction={{sort_state_next}}">State{{sort_state}}</a></th>
<th><a href="/auctions?sort=price&direction={{sort_price_next}}">Bid{{sort_price}}</a></th>
<th></th>
</tr>
</thead>
<tbody>
{{domains | safe}}
</tbody>
</table>
</div></div>
</div>
</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 2025</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>

View File

@ -1,8 +0,0 @@
<div class="col-md-6 col-xl-3 mb-4">
<div class="card shadow border-start-warning py-2">
<div class="card-body">
<div class="text-uppercase fw-bold text-xs mb-1"><span style="color: var(--bs-dark);">{{name}}</span></div>
<div class="text-dark fw-bold h5 mb-0"><span>{{output | safe}}</span></div>
</div>
</div>
</div>

View File

@ -2,7 +2,7 @@
<div class="card shadow border-start-warning py-2">
<div class="card-body">
<div class="text-uppercase fw-bold text-xs mb-1"><span style="color: var(--bs-dark);">{{name}}</span></div>
<div class="text-dark fw-bold h5 mb-0"><span>{{output | safe}}</span></div>
<div class="text-dark fw-bold h5 mb-0"><span>{{output}}</span></div>
</div>
</div>
</div>

View File

@ -1,5 +1,4 @@
<span style="display: block;font-size: 12px;">TX: {{tx}}</span>
<span style="display: block;">Check your transaction on a block explorer</span>
<a class="card-link" href="https://niami.io/tx/{{tx}}" target="_blank">Niami</a>
<a class="card-link" href="https://3xpl.com/handshake/transaction/{{tx}}" target="_blank">3xpl</a>
<a class="card-link" href="https://hns.cymon.de/tx/{{tx}}" target="_blank">Cymon.de</a>
<a class="card-link" href="https://3xpl.com/handshake/transaction/{{tx}}" target="_blank">3xpl</a>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -76,7 +74,7 @@
</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 2025</span></div>
<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>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -75,7 +73,7 @@
</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 2025</span></div>
<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>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,10 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -123,7 +120,7 @@
</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 2025</span></div>
<div class="text-center my-auto copyright"><span>Copyright © FireWallet 2023</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>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<ul class="navbar-nav text-light" id="accordionSidebar">
<li class="nav-item"><a class="nav-link active" 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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -64,7 +62,7 @@
</nav>
<div class="container-fluid">
<div class="d-sm-flex justify-content-between align-items-center mb-4">
<h3 class="text-dark mb-0">Dashboard</h3><a class="btn btn-primary btn-sm d-none d-sm-inline-block" role="button" href="/report" target="_blank"><i class="fas fa-download fa-sm text-white-50"></i>&nbsp;Generate Report</a>
<h3 class="text-dark mb-0">Dashboard</h3><a class="btn btn-primary btn-sm d-none d-sm-inline-block" role="button" href="/report"><i class="fas fa-download fa-sm text-white-50"></i>&nbsp;Generate Report</a>
</div>
<div class="row">
<div class="col-md-6 col-xl-3 mb-4">
@ -72,8 +70,8 @@
<div class="card-body">
<div class="row align-items-center no-gutters">
<div class="col me-2">
<div class="text-uppercase text-primary fw-bold text-xs mb-1"><span style="color: var(--bs-dark);">HNS Available</span></div>
<div class="text-dark fw-bold h5 mb-0"><span><img src="/assets/img/HNS.png" width="20px">&nbsp;<span id="wallet-available">0.00</span></span></div>
<div class="text-uppercase text-primary fw-bold text-xs mb-1"><span>HNS Available</span></div>
<div class="text-dark fw-bold h5 mb-0"><span><img src="/assets/img/HNS.png" width="20px">&nbsp;{{available}}</span></div>
</div>
<div class="col-auto"><i class="fas fa-dollar-sign fa-2x text-gray-300"></i></div>
</div>
@ -86,7 +84,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>HNS Total</span></div>
<div class="text-dark fw-bold h5 mb-0"><span><img src="/assets/img/HNS.png" width="20px">&nbsp;<span id="wallet-total">0.00</span></span></div>
<div class="text-dark fw-bold h5 mb-0"><span><img src="/assets/img/HNS.png" width="20px">&nbsp;{{total}}</span></div>
</div>
<div class="col-auto"><i class="fas fa-dollar-sign fa-2x text-gray-300"></i></div>
</div>
@ -101,7 +99,7 @@
<div class="text-uppercase text-info fw-bold text-xs mb-1"><span>Domains</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-domainCount">0</span></div>
<div class="text-dark fw-bold h5 mb-0 me-3"><span>{{domain_count}}</span></div>
</div>
</div>
</div>
@ -115,7 +113,7 @@
<div class="row align-items-center no-gutters">
<div class="col me-2">
<div class="text-uppercase text-warning fw-bold text-xs mb-1"><span>Pending Transactions</span></div>
<div class="text-dark fw-bold h5 mb-0"><span id="wallet-pending">0</span></div>
<div class="text-dark fw-bold h5 mb-0"><span>{{pending}}</span></div>
</div>
<div class="col-auto"><svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="1em" viewBox="0 0 24 24" width="1em" fill="currentColor" class="fa-2x text-gray-300">
<g>
@ -128,9 +126,8 @@
</div>
</div>
</div>
</div>
</div>{{plugins|safe}}
</div>
<div class="row" id="actions-row">{{plugins|safe}}</div>
<div class="row">
<div class="col">
<div class="card shadow mb-4">
@ -138,23 +135,6 @@
<h6 class="text-primary fw-bold m-0">Domains</h6>
</div>
<div class="card-body"><div class="table-responsive">
<table class="table" id="data-table">
<thead>
<tr>
<th onclick="sortTable(0)">Domain <span class="sort-indicator"></span></th>
<th onclick="sortTable(1)">Expires <span class="sort-indicator"></span></th>
<th onclick="sortTable(2)">Price Paid <span class="sort-indicator"></span></th>
<th><span class="sort-indicator"></span></th>
</tr>
</thead>
<tbody>
<!-- {{domains | safe}} -->
</tbody>
</table>
</div>
<!-- <div class="table-responsive">
<table class="table">
<thead>
<tr>
@ -168,7 +148,7 @@
{{domains | safe}}
</tbody>
</table>
</div> --></div>
</div></div>
</div>
</div>
</div>
@ -176,14 +156,13 @@
</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 2025</span></div>
<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>
<script src="/assets/js/dashboard.min.js"></script>
</body>
</html>

View File

@ -19,7 +19,6 @@
<div class="container">
<div class="row justify-content-center">
<div class="col-md-9 col-lg-12 col-xl-10">
<h1 class="text-center" style="color: var(--bs-danger);background: var(--bs-primary);">{{error}}</h1>
<div class="card shadow-lg o-hidden border-0 my-5">
<div class="card-body p-0">
<div class="row">
@ -32,21 +31,9 @@
<h4 class="text-dark mb-4">Welcome Back!</h4>
</div>
<form class="user" method="post">
<div class="mb-3"><img class="border rounded-circle img-profile" id="accountIcon" src="/api/v1/icon/primary" width="50px" height="50px" style="width: 50px;height: 50px;display: inline;"><select id="accountSelect" class="form-control form-select form-select-lg form-control-user" name="account" style="display: inline;width:calc(100% - 60px);margin-left:10px;" onchange="updateIcon()">
<div class="mb-3"><select class="form-control form-select form-select-lg form-control-user" name="account" value="default">
{{wallets|safe}}
</select>
<script>
function updateIcon() {
var select = document.getElementById("accountSelect");
var selectedValue = select.value;
document.getElementById("accountIcon").src = "/api/v1/icon/" + selectedValue;
}
document.addEventListener("DOMContentLoaded", function () {
updateIcon();
});
</script>
</div>
</select></div>
<div class="mb-3"><input class="form-control form-control-user" type="password" id="exampleInputPassword" placeholder="Password" name="password"></div><button class="btn btn-primary d-block btn-user w-100" type="submit">Login</button>
<hr>
</form>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,32 +28,32 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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" style="padding-bottom: 25px;">
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -138,20 +136,10 @@ function checkAddress(inputValue) {
</div>
</div>
</div>
<div class="container-fluid" style="margin-top: 50px;">
<div class="card">
<div class="card-body">
<h4 class="card-title" style="display: inline-block;">Sign Message</h4>
<form action="/manage/{{domain}}/sign" style="display: {% if finalize_time=='' %} block {% else %} none {% endif %};">
<div style="margin-top: 25px;"><label class="form-label">Message</label><input class="form-control" type="text" placeholder="Message to sign" name="message" value="{{message}}"></div><input class="btn btn-primary" type="submit" value="Sign" style="margin-top: 16px;">
</form>
</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 2025</span></div>
<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>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -69,7 +67,7 @@
</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 2025</span></div>
<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>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -69,7 +67,7 @@
</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 2025</span></div>
<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>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -65,13 +63,13 @@
<h1 class="text-center" style="color: rgb(255,0,0);">{{error}}</h1>
<div class="container-fluid" style="margin-bottom: 20px;">
<h3 class="text-dark mb-1">{{name}}</h3>
<h4 class="text-dark mb-1">{{description|safe}}</h4>
<h6 class="text-dark mb-1">Author: {{author}}<br>Version: {{version}}<br>Source: {{source}}</h6>{{functions|safe}}
<h4 class="text-dark mb-1">{{description}}</h4>
<h6 class="text-dark mb-1">Author: {{author}}<br>Version: {{version}}</h6>{{functions|safe}}
</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 2025</span></div>
<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>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -70,7 +68,7 @@
</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 2025</span></div>
<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>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -68,13 +66,13 @@
<div class="card" style="margin: auto;max-width: 500px;margin-top: 50px;">
<div class="card-body text-center">
<h4 class="card-title">{{address}}</h4><img src="/qr/{{address}}">
<p class="card-text">Use this address to receive HNS or Handshake domains from other people or wallets.</p><textarea id="data" style="display: none;">{{address}}</textarea><button class="btn btn-primary" id="copyButton" type="button" onclick="copyToClipboard()">Copy</button>
<p class="card-text">Use this address to receive HNS or Handshake domains from other people or wallets.</p><a class="card-link" id="copyLink" href="javascript:;" address="{{address}}" onclick="copyAddress()">Copy</a>
</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 2025</span></div>
<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>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -65,9 +63,8 @@
<div class="container-fluid">
<div class="card">
<div class="card-body">
<h4 class="d-none d-sm-none d-md-none d-lg-inline-block d-xl-inline-block card-title">{{domain}}/<span class="stick-right">{{next}}</span></h4>
<h4 class="d-print-none d-sm-inline-block d-md-inline-block d-lg-none d-xl-none d-xxl-none card-title">{{domain}}/<br><br><span class="stick-right">{{next}}</span></h4>
<h6 class="text-muted card-subtitle mb-2"><br>{{state}}</h6>
<h4 class="card-title">{{domain}}/<span class="stick-right">{{next}}</span></h4>
<h6 class="text-muted card-subtitle mb-2">{{state}}</h6>
<h6 class="text-muted card-subtitle mb-2">Owner: {{owner}}</h6><a class="btn btn-primary" role="button" style="margin-right: 25px;" href="/manage/{{domain}}">Manage</a><a class="btn btn-primary" role="button" href="/auction/{{domain}}">Auction</a>
</div>
</div>
@ -115,7 +112,7 @@
</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 2025</span></div>
<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>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -101,7 +99,7 @@ function checkAddress(inputValue) {
var inputField = document.getElementById('address');
inputField.addEventListener('blur', handleBlur);
</script></div>
<div style="margin-top: 25px;"><label class="form-label">Amount</label><input class="form-control" type="text" id="amount" placeholder="0.00000" name="amount" style="margin-bottom: 10px;" value="{{amount}}"><span>Available to send: {{max}} HNS</span><button class="btn btn-secondary btn-sm" id="maxButton" type="button" style="margin-left: 25px;">Send Max</button><script>
<div style="margin-top: 25px;"><label class="form-label">Amount</label><input class="form-control" type="text" id="amount" placeholder="0.00000" name="amount" style="margin-bottom: 10px;" value="{{amount}}"><span>Available to send: {{max}} HNS</span><button class="btn btn-primary btn-sm" id="maxButton" type="button" style="margin-left: 25px;background: var(--bs-primary-bg-subtle);">Send Max</button><script>
// Function to fill in the form input
function fillInput() {
// Get the input field and set its value
@ -113,12 +111,12 @@ function checkAddress(inputValue) {
var fillButton = document.getElementById('maxButton');
fillButton.addEventListener('click', fillInput);
</script></div>
<div class="text-center" style="margin-top: 25px;"><input class="btn btn-secondary" type="submit" value="Send"></div>
<div class="text-center" style="margin-top: 25px;"><input class="btn btn-primary" type="submit" value="Send" style="background: var(--bs-primary-bg-subtle);"></div>
</form>
</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 2025</span></div>
<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>

View File

@ -13,16 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/ionicons.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -31,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -43,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" id="wallet-icon" src="/api/v1/wallet/icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -68,7 +65,7 @@
<h3 class="mb-1" style="text-align: center;color: rgb(0,255,0);">{{success}}</h3>
<div class="card">
<div class="card-body">
<h4 class="card-title">Node Settings</h4><small>HSD Version: v{{hsd_version}}</small>
<h4 class="card-title">Node Settings</h4>
<h6 class="text-muted card-subtitle mb-2">Settings that affect all wallets</h6>
<ul class="list-group">
<li class="list-group-item">
@ -101,34 +98,14 @@
<h3>xPub Key</h3><span>Get your xPub key</span>
</div>
</li>
<li class="list-group-item">
<form id="uploadForm" action="/settings/upload" method="post" enctype="multipart/form-data">
<div>
<h3>Account Icon</h3><span>Customise your account</span><script>
function autoSubmit() {
document.getElementById('uploadForm').submit();
}
</script><input class="form-control" type="file" name="image" onchange="autoSubmit()">
</div>
</form>
</li>
</ul>
</div>
</div>
</div>
<div class="container-fluid" style="margin-top: 50px;margin-bottom: 50px;">
<div class="card">
<div class="card-body">
<h4 class="card-title">About</h4>
<h6 class="text-muted card-subtitle mb-2">FireWallet is a UI to allow easy connection with HSD created by <a href="https://nathan.woodburn.au" target="_blank">Nathan.Woodburn/</a> and freely available. Please contact him <a href="https://l.woodburn.au/contact" target="_blank">here</a> if you would like to request any features or report any bugs.<br>FireWallet version: <code>{{version}}</code></h6>
<div class="text-center"><a href="https://github.com/nathanwoodburn/firewalletbrowser" style="margin: 15px;color: var(--bs-emphasis-color);text-decoration:none;" target="_blank"><i class="icon ion-social-github" style="color: var(--bs-emphasis-color);"></i>&nbsp;Github</a><a href="https://firewallet.au" style="margin: 15px;color: var(--bs-emphasis-color);text-decoration:none;" target="_blank"><i class="icon ion-ios-information" style="color: var(--bs-emphasis-color);"></i>&nbsp;Website</a><a href="https://l.woodburn.au/donate" style="margin: 15px;color: var(--bs-emphasis-color);text-decoration:none;" target="_blank"><i class="icon ion-social-usd" style="color: var(--bs-emphasis-color);"></i>&nbsp;Donate to support development</a></div>
</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 2025</span></div>
<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>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -67,13 +65,13 @@
</div>
<div class="card" style="max-width: 500px;margin: auto;margin-top: 50px;">
<div class="card-body">
<h4 class="card-title">Your transaction has been sent and will be mined soon.</h4><span style="display: block;font-size: 12px;">TX: {{tx}}</span><span style="display: block;">Check your transaction on a block explorer</span><a class="card-link" href="https://niami.io/tx/{{tx}}" target="_blank">Niami</a><a class="card-link" href="https://3xpl.com/handshake/transaction/{{tx}}" target="_blank">3xpl</a><a class="card-link" href="https://hns.cymon.de/tx/{{tx}}" target="_blank">HNS.Cymon.de</a>
<h4 class="card-title">Your transaction has been sent and will be mined soon.</h4><span style="display: block;font-size: 12px;">TX: {{tx}}</span><span style="display: block;">Check your transaction on a block explorer</span><a class="card-link" href="https://niami.io/tx/{{tx}}" target="_blank">Niami</a><a class="card-link" href="https://3xpl.com/handshake/transaction/{{tx}}" target="_blank">3xpl</a>
</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 2025</span></div>
<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>

View File

@ -13,15 +13,13 @@
<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&amp;display=swap">
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css">
<link rel="stylesheet" href="/assets/fonts/font-awesome.min.css">
<link rel="stylesheet" href="/assets/fonts/material-icons.min.css">
<link rel="stylesheet" href="/assets/fonts/fontawesome5-overrides.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 toggled" style="background: var(--bs-primary-border-subtle);">
<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>
@ -30,11 +28,11 @@
<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="/auctions"><i class="fa fa-gavel"></i><span>Auctions</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>
<li class="nav-item"><a class="nav-link" href="/plugins"><i class="material-icons">code</i><span>Plugins</span></a><a class="nav-link" href="/settings"><i class="material-icons">settings</i><span>Settings</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);">
@ -42,20 +40,20 @@
<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}}" style="color: var(--bs-dark-text-emphasis);background: var(--bs-light);"><button class="btn btn-primary py-0" type="submit"><i class="fas fa-search"></i></button></div>
</form><span style="color: var(--bs-dark);">Sync: <span id="hsd-sync">{{sync}}</span>%</span><span style="color: var(--bs-dark);margin-left: 10px;">Wallet:&nbsp;<span id="wallet-sync">{{wallet_status}}</span></span><span style="color: var(--bs-dark);margin-left: 10px;">Height: <span id="hsd-height">{{height}}</span></span>
<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" action="/search" method="get">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ..." name="q" value="{{search_term}}">
<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" style="color: var(--bs-dark);">{{account}}</span><img class="border rounded-circle img-profile" src="/api/v1/wallet/icon" id="wallet-icon"></a>
<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>&nbsp;Logout</a></div>
</div>
</li>
@ -65,17 +63,8 @@
<div class="container-fluid">
<h3 class="text-dark mb-4">Transactions</h3>
<div class="card shadow">
<div class="card-header py-3" style="padding: 16px;">
<div style="height: 38px;">
<p class="text-primary m-0 fw-bold" style="display: inline-block;">Transactions</p><div class="btn-group" role="group" style="right: 16px;top: 16px;position: absolute;height: 38px;">
{% if page != 1 %}
<a class="btn btn-primary" role="button" href="/tx?page={{page-1}}">Prev</a>
{% endif %}
{% if txCount == 100 %}
<a class="btn btn-primary" role="button" href="/tx?page={{page+1}}">Next</a>
{% endif %}
</div>
</div>
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Transactions</p>
</div>
<div class="card-body"><div id="dataTable" class="table-responsive table mt-2" role="grid" aria-describedby="dataTable_info">
<table id="dataTable" class="table my-0">
@ -107,7 +96,7 @@
</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 2025</span></div>
<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>

View File

@ -1 +1 @@
[data-bs-theme=dark]{--bs-primary:#000000;--bs-primary-rgb:0,0,0;--bs-primary-text-emphasis:#666666;--bs-primary-bg-subtle:#000000;--bs-primary-border-subtle:#000000;--bs-light:#404040;--bs-light-rgb:64,64,64;--bs-light-text-emphasis:#8C8C8C;--bs-light-bg-subtle:#0D0D0D;--bs-light-border-subtle:#262626;--bs-dark:#ffffff;--bs-dark-rgb:255,255,255;--bs-dark-text-emphasis:#FFFFFF;--bs-dark-bg-subtle:#333333;--bs-dark-border-subtle:#999999}.btn-primary[data-bs-theme=dark],[data-bs-theme=dark] .btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#000000;--bs-btn-border-color:#000000;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#000000;--bs-btn-hover-border-color:#000000;--bs-btn-focus-shadow-rgb:217,217,217;--bs-btn-active-color:#fff;--bs-btn-active-bg:#000000;--bs-btn-active-border-color:#000000;--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#000000;--bs-btn-disabled-border-color:#000000}.btn-outline-primary[data-bs-theme=dark],[data-bs-theme=dark] .btn-outline-primary{--bs-btn-color:#000000;--bs-btn-border-color:#000000;--bs-btn-focus-shadow-rgb:0,0,0;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#000000;--bs-btn-hover-border-color:#000000;--bs-btn-active-color:#fff;--bs-btn-active-bg:#000000;--bs-btn-active-border-color:#000000;--bs-btn-disabled-color:#000000;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#000000}.btn-light[data-bs-theme=dark],[data-bs-theme=dark] .btn-light{--bs-btn-color:#fff;--bs-btn-bg:#404040;--bs-btn-border-color:#404040;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#363636;--bs-btn-hover-border-color:#333333;--bs-btn-focus-shadow-rgb:226,226,226;--bs-btn-active-color:#fff;--bs-btn-active-bg:#333333;--bs-btn-active-border-color:#303030;--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#404040;--bs-btn-disabled-border-color:#404040}.btn-outline-light[data-bs-theme=dark],[data-bs-theme=dark] .btn-outline-light{--bs-btn-color:#404040;--bs-btn-border-color:#404040;--bs-btn-focus-shadow-rgb:64,64,64;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#404040;--bs-btn-hover-border-color:#404040;--bs-btn-active-color:#fff;--bs-btn-active-bg:#404040;--bs-btn-active-border-color:#404040;--bs-btn-disabled-color:#404040;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#404040}.btn-dark[data-bs-theme=dark],[data-bs-theme=dark] .btn-dark{--bs-btn-color:#000000;--bs-btn-bg:#ffffff;--bs-btn-border-color:#ffffff;--bs-btn-hover-color:#000000;--bs-btn-hover-bg:#FFFFFF;--bs-btn-hover-border-color:#FFFFFF;--bs-btn-focus-shadow-rgb:38,38,38;--bs-btn-active-color:#000000;--bs-btn-active-bg:#FFFFFF;--bs-btn-active-border-color:#FFFFFF;--bs-btn-disabled-color:#000000;--bs-btn-disabled-bg:#ffffff;--bs-btn-disabled-border-color:#ffffff}.btn-outline-dark[data-bs-theme=dark],[data-bs-theme=dark] .btn-outline-dark{--bs-btn-color:#ffffff;--bs-btn-border-color:#ffffff;--bs-btn-focus-shadow-rgb:255,255,255;--bs-btn-hover-color:#000000;--bs-btn-hover-bg:#ffffff;--bs-btn-hover-border-color:#ffffff;--bs-btn-active-color:#000000;--bs-btn-active-bg:#ffffff;--bs-btn-active-border-color:#ffffff;--bs-btn-disabled-color:#ffffff;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffffff}::-webkit-resizer{display:none}.stick-right{position:absolute;right:25px}.error:after{content:attr(data-text);position:absolute;left:2px;text-shadow:-1px 0 #e74a3b;top:0;color:#5a5c69;background:var(--bs-primary);overflow:hidden;clip:rect(0,900px,0,0);animation:2s linear infinite alternate-reverse noise-anim}.error:before{content:attr(data-text);position:absolute;left:-2px;text-shadow:1px 0 #4e73df;top:0;color:#5a5c69;background:var(--bs-primary);overflow:hidden;clip:rect(0,900px,0,0);animation:3s linear infinite alternate-reverse noise-anim-2}
[data-bs-theme=dark]{--bs-primary:#000000;--bs-primary-rgb:0,0,0;--bs-primary-text-emphasis:#666666;--bs-primary-bg-subtle:#000000;--bs-primary-border-subtle:#000000;--bs-light:#404040;--bs-light-rgb:64,64,64;--bs-light-text-emphasis:#8C8C8C;--bs-light-bg-subtle:#0D0D0D;--bs-light-border-subtle:#262626;--bs-dark:#ffffff;--bs-dark-rgb:255,255,255;--bs-dark-text-emphasis:#FFFFFF;--bs-dark-bg-subtle:#333333;--bs-dark-border-subtle:#999999}.btn-primary[data-bs-theme=dark],[data-bs-theme=dark] .btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#000000;--bs-btn-border-color:#000000;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#000000;--bs-btn-hover-border-color:#000000;--bs-btn-focus-shadow-rgb:217,217,217;--bs-btn-active-color:#fff;--bs-btn-active-bg:#000000;--bs-btn-active-border-color:#000000;--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#000000;--bs-btn-disabled-border-color:#000000}.btn-outline-primary[data-bs-theme=dark],[data-bs-theme=dark] .btn-outline-primary{--bs-btn-color:#000000;--bs-btn-border-color:#000000;--bs-btn-focus-shadow-rgb:0,0,0;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#000000;--bs-btn-hover-border-color:#000000;--bs-btn-active-color:#fff;--bs-btn-active-bg:#000000;--bs-btn-active-border-color:#000000;--bs-btn-disabled-color:#000000;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#000000}.btn-light[data-bs-theme=dark],[data-bs-theme=dark] .btn-light{--bs-btn-color:#fff;--bs-btn-bg:#404040;--bs-btn-border-color:#404040;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#363636;--bs-btn-hover-border-color:#333333;--bs-btn-focus-shadow-rgb:226,226,226;--bs-btn-active-color:#fff;--bs-btn-active-bg:#333333;--bs-btn-active-border-color:#303030;--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#404040;--bs-btn-disabled-border-color:#404040}.btn-outline-light[data-bs-theme=dark],[data-bs-theme=dark] .btn-outline-light{--bs-btn-color:#404040;--bs-btn-border-color:#404040;--bs-btn-focus-shadow-rgb:64,64,64;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#404040;--bs-btn-hover-border-color:#404040;--bs-btn-active-color:#fff;--bs-btn-active-bg:#404040;--bs-btn-active-border-color:#404040;--bs-btn-disabled-color:#404040;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#404040}.btn-dark[data-bs-theme=dark],[data-bs-theme=dark] .btn-dark{--bs-btn-color:#000000;--bs-btn-bg:#ffffff;--bs-btn-border-color:#ffffff;--bs-btn-hover-color:#000000;--bs-btn-hover-bg:#FFFFFF;--bs-btn-hover-border-color:#FFFFFF;--bs-btn-focus-shadow-rgb:38,38,38;--bs-btn-active-color:#000000;--bs-btn-active-bg:#FFFFFF;--bs-btn-active-border-color:#FFFFFF;--bs-btn-disabled-color:#000000;--bs-btn-disabled-bg:#ffffff;--bs-btn-disabled-border-color:#ffffff}.btn-outline-dark[data-bs-theme=dark],[data-bs-theme=dark] .btn-outline-dark{--bs-btn-color:#ffffff;--bs-btn-border-color:#ffffff;--bs-btn-focus-shadow-rgb:255,255,255;--bs-btn-hover-color:#000000;--bs-btn-hover-bg:#ffffff;--bs-btn-hover-border-color:#ffffff;--bs-btn-active-color:#000000;--bs-btn-active-bg:#ffffff;--bs-btn-active-border-color:#ffffff;--bs-btn-disabled-color:#ffffff;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffffff}.stick-right{position:absolute;right:25px}.error:after{content:attr(data-text);position:absolute;left:2px;text-shadow:-1px 0 #e74a3b;top:0;color:#5a5c69;background:var(--bs-primary);overflow:hidden;clip:rect(0,900px,0,0);animation:2s linear infinite alternate-reverse noise-anim}.error:before{content:attr(data-text);position:absolute;left:-2px;text-shadow:1px 0 #4e73df;top:0;color:#5a5c69;background:var(--bs-primary);overflow:hidden;clip:rect(0,900px,0,0);animation:3s linear infinite alternate-reverse noise-anim-2}

View File

@ -1 +0,0 @@
[data-bs-theme=dark]{--bs-light:#ffffff;--bs-light-rgb:255,255,255;--bs-light-text-emphasis:#FFFFFF;--bs-light-bg-subtle:#333333;--bs-light-border-subtle:#999999;--bs-dark:#000000;--bs-dark-rgb:0,0,0;--bs-dark-text-emphasis:#666666;--bs-dark-bg-subtle:#000000;--bs-dark-border-subtle:#000000}.btn-light[data-bs-theme=dark],[data-bs-theme=dark] .btn-light{--bs-btn-color:#000000;--bs-btn-bg:#ffffff;--bs-btn-border-color:#ffffff;--bs-btn-hover-color:#000000;--bs-btn-hover-bg:#D9D9D9;--bs-btn-hover-border-color:#CCCCCC;--bs-btn-focus-shadow-rgb:38,38,38;--bs-btn-active-color:#000000;--bs-btn-active-bg:#CCCCCC;--bs-btn-active-border-color:#BFBFBF;--bs-btn-disabled-color:#000000;--bs-btn-disabled-bg:#ffffff;--bs-btn-disabled-border-color:#ffffff}.btn-outline-light[data-bs-theme=dark],[data-bs-theme=dark] .btn-outline-light{--bs-btn-color:#ffffff;--bs-btn-border-color:#ffffff;--bs-btn-focus-shadow-rgb:255,255,255;--bs-btn-hover-color:#000000;--bs-btn-hover-bg:#ffffff;--bs-btn-hover-border-color:#ffffff;--bs-btn-active-color:#000000;--bs-btn-active-bg:#ffffff;--bs-btn-active-border-color:#ffffff;--bs-btn-disabled-color:#ffffff;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffffff}.btn-dark[data-bs-theme=dark],[data-bs-theme=dark] .btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#000000;--bs-btn-border-color:#000000;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#000000;--bs-btn-hover-border-color:#000000;--bs-btn-focus-shadow-rgb:217,217,217;--bs-btn-active-color:#fff;--bs-btn-active-bg:#000000;--bs-btn-active-border-color:#000000;--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#000000;--bs-btn-disabled-border-color:#000000}.btn-outline-dark[data-bs-theme=dark],[data-bs-theme=dark] .btn-outline-dark{--bs-btn-color:#000000;--bs-btn-border-color:#000000;--bs-btn-focus-shadow-rgb:0,0,0;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#000000;--bs-btn-hover-border-color:#000000;--bs-btn-active-color:#fff;--bs-btn-active-bg:#000000;--bs-btn-active-border-color:#000000;--bs-btn-disabled-color:#000000;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#000000}::-webkit-resizer{display:none}.stick-right{position:absolute;right:25px}.error:after{content:attr(data-text);position:absolute;left:2px;text-shadow:-1px 0 #e74a3b;top:0;color:#5a5c69;background:var(--bs-primary);overflow:hidden;clip:rect(0,900px,0,0);animation:2s linear infinite alternate-reverse noise-anim}.error:before{content:attr(data-text);position:absolute;left:-2px;text-shadow:1px 0 #4e73df;top:0;color:#5a5c69;background:var(--bs-primary);overflow:hidden;clip:rect(0,900px,0,0);animation:3s linear infinite alternate-reverse noise-anim-2}