feat/ponder-lm-indexing (#142)
This commit is contained in:
parent
de3c8eef94
commit
31063379a8
107 changed files with 12517 additions and 367 deletions
167
tmp/usertest-results/BALANCE-BUG-ANALYSIS.md
Normal file
167
tmp/usertest-results/BALANCE-BUG-ANALYSIS.md
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
# KRK Balance Loading Bug - Root Cause Analysis
|
||||
|
||||
## Summary
|
||||
After swapping ETH→KRK on the cheats page, the KRK token balance takes 10-90+ seconds to load (or never loads), causing "Insufficient Balance" errors on the stake page. This blocked 2 of 5 user test personas from staking.
|
||||
|
||||
## Root Cause
|
||||
|
||||
### The Problem
|
||||
The `useWallet()` composable fetches the KRK token balance **only** when:
|
||||
1. The wallet account changes (address or chainId)
|
||||
2. The blockchain chain changes
|
||||
|
||||
**There is NO polling mechanism** and **no automatic refresh after transactions**.
|
||||
|
||||
### The Flow
|
||||
1. User swaps ETH→KRK in `CheatsView.vue` via `buyKrk()`
|
||||
2. The swap transaction completes successfully
|
||||
3. **`buyKrk()` does NOT call `wallet.loadBalance()`** after the transaction
|
||||
4. User navigates to Stake page
|
||||
5. Navigation doesn't trigger account/chain change events
|
||||
6. `StakeHolder.vue` reads stale `wallet.balance.value` (still 0 KRK)
|
||||
7. `maxStakeAmount` computed property returns 0
|
||||
8. User sees "Insufficient Balance"
|
||||
|
||||
### Code Evidence
|
||||
|
||||
**useWallet.ts (lines 82-98):**
|
||||
```typescript
|
||||
async function loadBalance() {
|
||||
logger.contract('loadBalance');
|
||||
const userAddress = account.value.address;
|
||||
if (!userAddress) {
|
||||
return 0n;
|
||||
}
|
||||
let publicClient = getWalletPublicClient();
|
||||
if (!publicClient) {
|
||||
publicClient = await syncWalletPublicClient();
|
||||
}
|
||||
if (!publicClient) {
|
||||
return 0n;
|
||||
}
|
||||
const value = (await publicClient.readContract({
|
||||
abi: HarbContract.abi,
|
||||
address: HarbContract.contractAddress,
|
||||
functionName: 'balanceOf',
|
||||
args: [userAddress],
|
||||
})) as bigint;
|
||||
// ... sets balance.value
|
||||
}
|
||||
```
|
||||
|
||||
**Balance refresh triggers (lines 102-154):**
|
||||
- `watchAccount()` - only on address/chainId change
|
||||
- `watchChainId()` - only on explicit chain switch
|
||||
- **NO interval polling**
|
||||
- **NO transaction completion hooks**
|
||||
|
||||
**CheatsView.vue buyKrk() (lines ~941-1052):**
|
||||
```typescript
|
||||
async function buyKrk() {
|
||||
// ... performs swap transaction
|
||||
await writeContract(wagmiConfig, {
|
||||
abi: SWAP_ROUTER_ABI,
|
||||
address: router,
|
||||
functionName: 'exactInputSingle',
|
||||
args: [/* swap params */],
|
||||
chainId,
|
||||
});
|
||||
toast.success('Swap submitted. Watch your wallet for KRK.');
|
||||
// ❌ MISSING: wallet.loadBalance() call here!
|
||||
} finally {
|
||||
swapping.value = false;
|
||||
}
|
||||
```
|
||||
|
||||
**StakeHolder.vue (lines 220-227):**
|
||||
```typescript
|
||||
const maxStakeAmount = computed(() => {
|
||||
if (wallet.balance?.value) {
|
||||
return bigInt2Number(wallet.balance.value, 18);
|
||||
}
|
||||
return 0; // ❌ Returns 0 when balance is stale
|
||||
});
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
### Quick Fix (Recommended)
|
||||
Add `wallet.loadBalance()` call after the swap transaction completes in `CheatsView.vue`:
|
||||
|
||||
```typescript
|
||||
async function buyKrk() {
|
||||
if (!canSwap.value || swapping.value) return;
|
||||
try {
|
||||
swapping.value = true;
|
||||
// ... existing swap logic ...
|
||||
|
||||
await writeContract(wagmiConfig, {
|
||||
abi: SWAP_ROUTER_ABI,
|
||||
address: router,
|
||||
functionName: 'exactInputSingle',
|
||||
args: [/* swap params */],
|
||||
chainId,
|
||||
});
|
||||
|
||||
// ✅ FIX: Refresh KRK balance after swap
|
||||
const { loadBalance } = useWallet();
|
||||
await loadBalance();
|
||||
|
||||
toast.success('Swap submitted. Watch your wallet for KRK.');
|
||||
} catch (error: unknown) {
|
||||
toast.error(getErrorMessage(error, 'Swap failed'));
|
||||
} finally {
|
||||
swapping.value = false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Alternative Solutions (For Consideration)
|
||||
|
||||
1. **Add polling to useWallet():**
|
||||
- Poll balance every 5-10 seconds when wallet is connected
|
||||
- Pro: Auto-updates across all pages
|
||||
- Con: Increased RPC calls, may hit rate limits
|
||||
|
||||
2. **Vue Router navigation guard:**
|
||||
- Refresh balance on route enter
|
||||
- Pro: Works for all navigation patterns
|
||||
- Con: Slight delay on every page load
|
||||
|
||||
3. **Event bus for transaction completion:**
|
||||
- Emit event after any token-affecting transaction
|
||||
- Subscribe in useWallet to refresh balance
|
||||
- Pro: Clean separation of concerns
|
||||
- Con: More complex architecture
|
||||
|
||||
## Impact
|
||||
|
||||
### Severity: **CRITICAL**
|
||||
- Blocks core user flow (swap → stake)
|
||||
- 40% of test users affected (2/5 personas)
|
||||
- Confusing UX ("I just bought tokens, why can't I stake?")
|
||||
|
||||
### User Experience Issues
|
||||
1. No loading indicator for balance refresh
|
||||
2. No error message explaining the delay
|
||||
3. Users don't know to wait or refresh page
|
||||
4. Some users never see balance load (likely due to wallet/RPC issues)
|
||||
|
||||
## Recommended Action
|
||||
|
||||
1. ✅ **Immediate:** Implement the quick fix (add `loadBalance()` call after swap)
|
||||
2. 🔍 **Investigation:** Test why some balances "never" load - possible RPC/wallet issues?
|
||||
3. 💡 **Future:** Consider adding a manual "Refresh Balance" button on stake page
|
||||
4. 📊 **Monitoring:** Track balance load times in production
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] Swap ETH→KRK on cheats page
|
||||
- [ ] Immediately navigate to stake page
|
||||
- [ ] Verify KRK balance displays correctly within 1-2 seconds
|
||||
- [ ] Test with multiple wallet providers (MetaMask, Coinbase Wallet)
|
||||
- [ ] Test with slow RPC endpoints
|
||||
- [ ] Verify balance updates after page navigation
|
||||
|
||||
## Files Modified
|
||||
- `/home/debian/harb/web-app/src/views/CheatsView.vue` (add loadBalance call)
|
||||
Loading…
Add table
Add a link
Reference in a new issue