feat/mempool-bids #2
Binary file not shown.
32
account.py
32
account.py
@@ -460,6 +460,23 @@ def isOwnDomain(account, name: str):
|
||||
return True
|
||||
return False
|
||||
|
||||
def isOwnPrevout(account, prevout: dict):
|
||||
if 'hash' not in prevout or 'index' not in prevout:
|
||||
return False
|
||||
# Get the address from the prevout
|
||||
address = getAddressFromCoin(prevout['hash'], prevout['index'])
|
||||
# Select the account
|
||||
hsw.rpc_selectWallet(account)
|
||||
account = hsw.rpc_getAccount(address)
|
||||
|
||||
if 'error' in account and account['error'] is not None:
|
||||
return False
|
||||
if 'result' not in account:
|
||||
return False
|
||||
if account['result'] == 'default':
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def getDomain(domain: str):
|
||||
# Get the domain
|
||||
@@ -1173,13 +1190,6 @@ def getMempoolBids():
|
||||
if 'error' in tx and tx['error'] is not None:
|
||||
print(f"Error getting tx {txid}: {tx['error']}")
|
||||
continue
|
||||
# bid_data.append({
|
||||
# 'bid': bid,
|
||||
# 'lockup': lockup,
|
||||
# 'revealed': revealed,
|
||||
# 'value': value,
|
||||
# 'sort_value': value if revealed else lockup # Use value for sorting if revealed, otherwise lockup
|
||||
# })
|
||||
if 'outputs' not in tx:
|
||||
print(f"Error getting outputs for tx {txid}")
|
||||
continue
|
||||
@@ -1204,7 +1214,8 @@ def getMempoolBids():
|
||||
'revealed': True,
|
||||
'height': -1,
|
||||
'value': output['value'],
|
||||
'sort_value': txInput['coin']['value']
|
||||
'sort_value': txInput['coin']['value'],
|
||||
'owner': "Unknown"
|
||||
}
|
||||
if name not in bids:
|
||||
bids[name] = []
|
||||
@@ -1222,11 +1233,10 @@ def getMempoolBids():
|
||||
'lockup': output['value'],
|
||||
'revealed': False,
|
||||
'height': -1,
|
||||
'sort_value': output['value']
|
||||
'sort_value': output['value'],
|
||||
'owner': "Unknown"
|
||||
}
|
||||
bids[name].append(bid)
|
||||
|
||||
|
||||
return bids
|
||||
|
||||
|
||||
|
||||
103
main.py
103
main.py
@@ -46,10 +46,15 @@ def blocks_to_time(blocks: int) -> str:
|
||||
elif blocks < 144:
|
||||
hours = blocks // 6
|
||||
minutes = (blocks % 6) * 10
|
||||
if minutes == 0:
|
||||
return f"{hours} hrs"
|
||||
|
||||
return f"{hours} hrs {minutes} mins"
|
||||
else:
|
||||
days = blocks // 144
|
||||
hours = (blocks % 144) // 6
|
||||
if hours == 0:
|
||||
return f"{days} days"
|
||||
return f"{days} days {hours} hrs"
|
||||
|
||||
|
||||
@@ -913,17 +918,18 @@ def auction(domain):
|
||||
state = domainInfo['info']['state']
|
||||
next_action = ''
|
||||
|
||||
bids = account_module.getBids(account,search_term)
|
||||
if bids == []:
|
||||
bids = "No bids found"
|
||||
next_action = f'<a href="/auction/{domain}/scan">Rescan Auction</a>'
|
||||
else:
|
||||
reveals = account_module.getReveals(account,search_term)
|
||||
for reveal in reveals:
|
||||
# Get TX
|
||||
revealInfo = account_module.getRevealTX(reveal)
|
||||
reveal['bid'] = revealInfo
|
||||
bids = render.bids(bids,reveals)
|
||||
# bids = account_module.getBids(account,search_term)
|
||||
bids = []
|
||||
# if bids == []:
|
||||
# bids = "No bids found"
|
||||
# next_action = f'<a href="/auction/{domain}/scan">Rescan Auction</a>'
|
||||
# else:
|
||||
# reveals = account_module.getReveals(account,search_term)
|
||||
# for reveal in reveals:
|
||||
# # Get TX
|
||||
# revealInfo = account_module.getRevealTX(reveal)
|
||||
# reveal['bid'] = revealInfo
|
||||
# bids = render.bids(bids,reveals)
|
||||
|
||||
stats = domainInfo['info']['stats'] if 'stats' in domainInfo['info'] else {}
|
||||
if state == 'CLOSED':
|
||||
@@ -944,10 +950,7 @@ def auction(domain):
|
||||
expires = domainInfo['info']['stats']['daysUntilExpire']
|
||||
next = f"Expires in ~{expires} days"
|
||||
|
||||
own_domains = account_module.getDomains(account)
|
||||
own_domains = [x['name'] for x in own_domains]
|
||||
own_domains = [x.lower() for x in own_domains]
|
||||
if search_term in own_domains:
|
||||
if account_module.isOwnDomain(account,domain):
|
||||
next_action = f'<a href="/manage/{domain}">Manage</a>'
|
||||
elif state == "REVOKED":
|
||||
next = "Available Now"
|
||||
@@ -1546,6 +1549,61 @@ def api_hsd(function):
|
||||
return jsonify({"result": account_module.getMempoolTxs()})
|
||||
if function == "mempoolBids":
|
||||
return jsonify({"result": account_module.getMempoolBids()})
|
||||
if function == "nextAuctionState":
|
||||
# Get the domain from the query parameters
|
||||
domain = request.args.get('domain')
|
||||
if not domain:
|
||||
return jsonify({"error": "No domain specified"}), 400
|
||||
domainInfo = account_module.getDomain(domain)
|
||||
if 'error' in domainInfo and domainInfo['error'] != None:
|
||||
return jsonify({"error": domainInfo['error']}), 400
|
||||
stats = domainInfo['info']['stats'] if 'stats' in domainInfo['info'] else {}
|
||||
state = domainInfo['info']['state']
|
||||
next_action = ""
|
||||
if state == 'CLOSED':
|
||||
if not domainInfo['info']['registered']:
|
||||
if account_module.isOwnDomain(account,domain):
|
||||
print("Waiting to be registered")
|
||||
state = 'PENDING REGISTER'
|
||||
next = "Pending Register"
|
||||
next_action = f'<a href="/auction/{domain}/register">Register Domain</a>'
|
||||
|
||||
else:
|
||||
print("Not registered")
|
||||
state = 'AVAILABLE'
|
||||
next = "Available Now"
|
||||
next_action = f'<a href="/auction/{domain}/open">Open Auction</a>'
|
||||
else:
|
||||
state = 'REGISTERED'
|
||||
expires = domainInfo['info']['stats']['daysUntilExpire']
|
||||
next = f"Expires in ~{expires} days"
|
||||
elif state == "REVOKED":
|
||||
next = "Available Now"
|
||||
next_action = f'<a href="/auction/{domain}/open">Open Auction</a>'
|
||||
elif state == 'OPENING':
|
||||
next = f"Bidding opens in {str(stats['blocksUntilBidding'])} blocks (~{blocks_to_time(stats['blocksUntilBidding'])})"
|
||||
elif state == 'BIDDING':
|
||||
next = f"Reveal in {stats['blocksUntilReveal']} blocks (~{blocks_to_time(stats['blocksUntilReveal'])})"
|
||||
if stats['blocksUntilReveal'] == 1:
|
||||
next += "<br>Bidding no longer possible"
|
||||
elif stats['blocksUntilReveal'] == 2:
|
||||
next += "<br>LAST CHANCE TO BID"
|
||||
elif stats['blocksUntilReveal'] == 3:
|
||||
next += f"<br>Next block is last chance to bid"
|
||||
elif stats['blocksUntilReveal'] < 6:
|
||||
next += f"<br>Last chance to bid in {stats['blocksUntilReveal']-2} blocks"
|
||||
|
||||
|
||||
elif state == 'REVEAL':
|
||||
next = f"Reveal ends in {str(stats['blocksUntilClose'])} blocks (~{blocks_to_time(stats['blocksUntilClose'])})"
|
||||
next_action = f'<a href="/auction/{domain}/reveal">Reveal All</a>'
|
||||
|
||||
return jsonify({
|
||||
"state": state,
|
||||
"next": next,
|
||||
"next_action": next_action
|
||||
})
|
||||
|
||||
|
||||
return jsonify({"error": "Invalid function", "result": "Invalid function"}), 400
|
||||
|
||||
@@ -1665,6 +1723,21 @@ def api_wallet(function):
|
||||
"page": page
|
||||
})
|
||||
|
||||
if function == "domainBids":
|
||||
domain = request.args.get('domain')
|
||||
if not domain:
|
||||
return jsonify({"error": "No domain specified"}), 400
|
||||
bids = account_module.getBids(account,domain)
|
||||
if bids == []:
|
||||
return jsonify({"result": [], "error": "No bids found"}), 404
|
||||
else:
|
||||
reveals = account_module.getReveals(account,domain)
|
||||
for reveal in reveals:
|
||||
# Get TX
|
||||
revealInfo = account_module.getRevealTX(reveal)
|
||||
reveal['bid'] = revealInfo
|
||||
bids = render.bids(bids,reveals)
|
||||
return jsonify({"result": bids})
|
||||
|
||||
if function == "icon":
|
||||
# Check if there is an icon
|
||||
|
||||
@@ -66,9 +66,9 @@
|
||||
<div class="container-fluid">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="stick-right">{{next_action|safe}}</div>
|
||||
<div id="next-action" class="stick-right">{{next_action|safe}}</div>
|
||||
<h4 class="card-title">{{rendered}}</h4>
|
||||
<h6 class="text-muted mb-2 card-subtitle">{{next | safe}}</h6>
|
||||
<h6 class="text-muted mb-2 card-subtitle" id="next">{{next | safe}}</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -96,11 +96,91 @@
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{bids | safe}}
|
||||
<tbody id="bids-tbody">
|
||||
<tr id="loading-row">
|
||||
<td colspan="5" class="text-center">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
Loading bids...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function loadBids() {
|
||||
const tbody = document.getElementById('bids-tbody');
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/v1/wallet/domainBids?domain={{search_term}}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok && data.result) {
|
||||
tbody.innerHTML = data.result;
|
||||
} else {
|
||||
tbody.innerHTML = '<tr><td colspan="5" class="text-center text-muted">No bids found. <a href="/auction/{{search_term}}/scan">Rescan Auction</a></td></tr>';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading bids:', error);
|
||||
tbody.innerHTML = '<tr><td colspan="5" class="text-center text-danger">Error loading bids</td></tr>';
|
||||
}
|
||||
|
||||
try {
|
||||
const nextStateResponse = await fetch(`/api/v1/hsd/nextAuctionState?domain={{search_term}}`);
|
||||
const nextStateData = await nextStateResponse.json();
|
||||
|
||||
if (nextStateResponse.ok && nextStateData.state) {
|
||||
document.getElementById('next').innerHTML = nextStateData.next;
|
||||
document.getElementById('next-action').innerHTML = nextStateData.next_action;
|
||||
} else {
|
||||
document.getElementById('next').innerHTML = 'Unknown';
|
||||
document.getElementById('next-action').innerHTML = '';
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching next state:', error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
try {
|
||||
const mempoolResponse = await fetch('/api/v1/hsd/mempoolBids');
|
||||
const mempoolData = await mempoolResponse.json();
|
||||
if (mempoolResponse.ok && mempoolData.result) {
|
||||
const domainBids = mempoolData.result['{{search_term}}'];
|
||||
if (domainBids && domainBids.length > 0) {
|
||||
let mempoolRows = '';
|
||||
domainBids.forEach(bid => {
|
||||
const bidValue = bid.revealed ? (bid.value / 1000000).toFixed(2) : 'Hidden until reveal';
|
||||
const lockupValue = (bid.lockup / 1000000).toFixed(2);
|
||||
const blindValue = bid.revealed ? (lockupValue - bidValue).toFixed(2) : 'Hidden until reveal';
|
||||
const type = bid.revealed ? 'Reveal' : 'Bid';
|
||||
mempoolRows += `<tr class="table-warning">
|
||||
<td>${lockupValue} HNS</td>
|
||||
<td>${bidValue} HNS</td>
|
||||
<td>${blindValue} HNS</td>
|
||||
<td>${bid.owner}</td>
|
||||
<td><a class='text-decoration-none' style='color: var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));' target='_blank' href='https://shakeshift.com/transaction/${bid.txid}'>Mempool ${type} 🔗</a></td>
|
||||
</tr>`;
|
||||
});
|
||||
tbody.innerHTML += mempoolRows;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading mempool bids:', error);
|
||||
// Don't override the main table content on mempool error
|
||||
}
|
||||
}
|
||||
|
||||
// Load bids when page loads
|
||||
document.addEventListener('DOMContentLoaded', loadBids);
|
||||
|
||||
// Auto-refresh bids every 20 seconds
|
||||
setInterval(loadBids, 20000);
|
||||
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user