Skip to content

Commit 76ae642

Browse files
swap bug fix and adding stats functionality
1 parent 32d528d commit 76ae642

File tree

6 files changed

+179
-6
lines changed

6 files changed

+179
-6
lines changed

chat-ui-quince/index.html

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<script> window.DOMPurify = DOMPurify; // Ensure it's accessible in module scripts </script>
1818

1919
<script type="module" src="/src/code.js"></script>
20+
<script type="module" src="/src/stats.js"></script>
2021
<link rel="stylesheet" crossorigin href="/src/style.css">
2122
</head>
2223
<body>
@@ -29,7 +30,14 @@
2930
</header>
3031
<div class="content-wrapper">
3132
<aside class="sidebar">
32-
<h2 class="sidebar-title">Your assets</h2>
33+
<div class="sidebar-header">
34+
<h2 class="sidebar-title">Your assets</h2>
35+
<button id="refresh-stats-btn" title="Refresh stats">
36+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
37+
<path d="M17.65 6.35A7.958 7.958 0 0 0 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0 1 12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" fill="currentColor"/>
38+
</svg>
39+
</button>
40+
</div>
3341
<table id="stats" class="stats-table">
3442
<thead>
3543
<tr class="stats-header-row">

chat-ui-quince/src/code.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { fetchStats, updateStats, clearStats } from './stats.js';
12

23
///////////////////////////////////////////////////
34
// Classes
@@ -249,7 +250,7 @@ const input = document.getElementById('message-input');
249250
const sendBtn = document.getElementById('send-btn');
250251
//const readOutLoudBtn = document.getElementById('read-out-loud-btn');
251252
const readOutLoudBtn = document.querySelector('.read-out-loud-btn');
252-
253+
const refreshStatsButton = document.getElementById('refresh-stats-btn');
253254

254255

255256

@@ -331,7 +332,10 @@ window.onload = function() {
331332
///////////////////////////////////////////////////
332333
// Event listeners
333334
///////////////////////////////////////////////////
334-
335+
refreshStatsButton.addEventListener('click', () => {
336+
fetchStats(token);
337+
});
338+
335339
sendBtn.addEventListener("click", handleSend);
336340

337341
input.addEventListener('keypress', function(e) {

chat-ui-quince/src/stats.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// src/stats.js
2+
3+
const API_BASE_URL = '/api/routes/chat'; // Adjust if your API prefix differs
4+
5+
// Stats fields mapping
6+
export const statsFields = {
7+
'flr': document.getElementById('value-flr'),
8+
'wflr': document.getElementById('value-wflr'),
9+
'usdc': document.getElementById('value-usdc'),
10+
'usdt': document.getElementById('value-usdt'),
11+
'joule': document.getElementById('value-joule'),
12+
'weth': document.getElementById('value-weth'),
13+
'sflr': document.getElementById('value-sflr'),
14+
'skflr': document.getElementById('value-skflr'),
15+
};
16+
17+
// Fetch stats from backend
18+
export async function fetchStats(token) {
19+
if (!token) {
20+
console.error('No token available, please sign in');
21+
return;
22+
}
23+
24+
try {
25+
const response = await fetch(`${API_BASE_URL}/stats`, {
26+
method: 'GET',
27+
headers: {
28+
'Authorization': `Bearer ${token}`,
29+
'Content-Type': 'application/json',
30+
},
31+
});
32+
33+
if (!response.ok) {
34+
throw new Error(`HTTP error! Status: ${response.status}`);
35+
}
36+
37+
const data = await response.json();
38+
updateStats(data);
39+
} catch (error) {
40+
console.error('Error fetching stats:', error);
41+
updateStatsWithError();
42+
}
43+
}
44+
45+
// Update stats in sidebar
46+
export function updateStats(balances) {
47+
Object.keys(statsFields).forEach(token => {
48+
const value = balances[token] !== undefined ? balances[token].toFixed(4) : '0.0000';
49+
statsFields[token].textContent = value;
50+
});
51+
}
52+
53+
// Clear or set stats to N/A
54+
export function clearStats() {
55+
Object.values(statsFields).forEach(field => {
56+
field.textContent = 'N/A';
57+
});
58+
}
59+
60+
function updateStatsWithError() {
61+
Object.values(statsFields).forEach(field => {
62+
field.textContent = 'N/A';
63+
});
64+
}

chat-ui-quince/src/style.css

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,4 +367,36 @@ body {
367367
.google-buttons {
368368
border-radius: 15px;
369369
font-size: 15px;
370+
}
371+
372+
373+
374+
.sidebar-header {
375+
display: flex;
376+
justify-content: space-between;
377+
align-items: center;
378+
margin-bottom: 10px;
379+
}
380+
381+
.sidebar-title {
382+
margin: 0;
383+
font-size: 1.5em;
384+
}
385+
386+
#refresh-stats-btn {
387+
background: none;
388+
border: none;
389+
cursor: pointer;
390+
padding: 5px;
391+
display: none; /* Hidden until signed in */
392+
}
393+
394+
#refresh-stats-btn svg {
395+
width: 20px;
396+
height: 20px;
397+
color: #333; /* Adjust color to match your theme */
398+
}
399+
400+
#refresh-stats-btn:hover svg {
401+
color: #007bff; /* Hover effect, adjust as needed */
370402
}

src/flare_ai_defai/api/routes/chat.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,18 @@ async def verify(token_request: TokenRequest):
145145
self.logger.error(f"Token verification failed: {e}")
146146
raise HTTPException(status_code=401, detail=f"Invalid token: {str(e)}")
147147

148+
@self._router.get("/stats")
149+
async def stats(user: UserInfo = Depends(get_current_user)) -> dict[str, float]:
150+
"""Return balances of FLR, WFLR, USDC, USDT, JOULE, and WETH for the user."""
151+
try:
152+
self.logger.debug("Fetching stats", user_id=user.user_id)
153+
balances = await self.get_token_balances(user)
154+
return balances
155+
except Exception as e:
156+
self.logger.error("Failed to fetch stats", error=str(e))
157+
raise HTTPException(status_code=500, detail=f"Failed to fetch balances: {str(e)}")
158+
159+
148160
@self._router.post("/")
149161
async def chat(
150162
message: ChatMessage,
@@ -560,3 +572,57 @@ async def handle_supply(self, message: str, user: UserInfo) -> dict[str, str]:
560572

561573

562574

575+
async def get_token_balances(self, user: UserInfo) -> dict[str, float]:
576+
"""Fetch balances of FLR and ERC-20 tokens for the user."""
577+
# ERC-20 ABI with balanceOf and decimals
578+
ERC20_ABI = [
579+
{
580+
"inputs": [{"internalType": "address", "name": "account", "type": "address"}],
581+
"name": "balanceOf",
582+
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
583+
"stateMutability": "view",
584+
"type": "function"
585+
},
586+
{
587+
"inputs": [],
588+
"name": "decimals",
589+
"outputs": [{"internalType": "uint8", "name": "", "type": "uint8"}],
590+
"stateMutability": "view",
591+
"type": "function"
592+
}
593+
]
594+
595+
# Token addresses from your provided data
596+
token_addresses = {
597+
"wflr": "0x1D80c49BbBCd1C0911346656B529DF9E5c2F783d",
598+
"joule": "0xE6505f92583103AF7ed9974DEC451A7Af4e3A3bE",
599+
"usdc": "0xFbDa5F676cB37624f28265A144A48B0d6e87d3b6",
600+
"usdt": "0x0B38e83B86d491735fEaa0a791F65c2B99535396",
601+
"weth": "0x1502FA4be69d526124D453619276FacCab275d3D"
602+
}
603+
604+
user_address = self.wallet_store.get_address(user)
605+
balances = {}
606+
607+
# Fetch FLR balance (native token)
608+
try:
609+
flr_balance_wei = self.blockchain.w3.eth.get_balance(user_address)
610+
balances["flr"] = float(self.blockchain.w3.from_wei(flr_balance_wei, "ether"))
611+
except Exception as e:
612+
self.logger.error("Failed to fetch FLR balance", error=str(e))
613+
balances["flr"] = 0.0
614+
615+
# Fetch ERC-20 token balances
616+
for token, address in token_addresses.items():
617+
try:
618+
contract = self.blockchain.w3.eth.contract(address=address, abi=ERC20_ABI)
619+
decimals = contract.functions.decimals().call()
620+
balance_wei = contract.functions.balanceOf(user_address).call()
621+
balance = balance_wei / (10 ** decimals)
622+
balances[token] = float(balance)
623+
except Exception as e:
624+
self.logger.error(f"Failed to fetch {token} balance", error=str(e))
625+
balances[token] = 0.0
626+
627+
self.logger.debug("Fetched balances", balances=balances, user_id=user.user_id)
628+
return balances

src/flare_ai_defai/blockchain/sparkdex.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,6 @@ def swap_erc20_tokens(self, token_in: str, token_out: str, amount_in: float):
370370

371371
def swap_erc20_tokens_tx(self, user: UserInfo, token_in: str, token_out: str, amount_in: float):
372372
slippage = 0.05
373-
amount_in = self.w3.to_wei(amount_in, unit="ether")
374373
universal_router_address = "0x8a1E35F5c98C4E85B36B7B253222eE17773b2781" # Replace with Flare's Universal Router if different
375374

376375
token_address = {
@@ -564,13 +563,13 @@ def swap_erc20_tokens_tx(self, user: UserInfo, token_in: str, token_out: str, am
564563
amount_out = amount_out_wei / (10 ** token_out_decimals)
565564
amount_out_min = int(amount_out_wei * (1 - slippage)) # Keep in wei units
566565
self.logger.debug("Estimated swap output", extra={
567-
"amount_in": amount_in, "token_in": token_in,
566+
"amount_in_wei": amount_in_wei, "token_in": token_in,
568567
"amount_out": amount_out, "token_out": token_out,
569568
"amount_out_min": amount_out_min
570569
})
571570

572571
# --- Step 1: Approve Universal Router to Spend wFLR ---
573-
approval_tx = contract_in.functions.approve(universal_router_address, amount_in).build_transaction({
572+
approval_tx = contract_in.functions.approve(universal_router_address, amount_in_wei).build_transaction({
574573
'from': self.wallet_store.get_address(user),
575574
'nonce': self.get_nonce(),
576575
"maxFeePerGas": base_fee + priority_fee,

0 commit comments

Comments
 (0)