fix: Delegate button silently fails when LPT allowance is partially approved
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 11
- Forks
- 26
- Avg merge
- 11h 58m
- Merged PRs (30d)
- 16
Description
## Problem
On the delegating widget, entering an amount that is below the wallet balance but above the current LPT allowance renders an enabled **Delegate** button that does nothing when clicked, no wallet prompt, no error. Smaller amounts work, so it looks like an arbitrary cap.
## Root cause
`/api/account-balance` returns `balance` and `allowance` as raw wei strings (`pages/api/account-balance/[address].tsx:44-47`), but `components/DelegatingWidget/Delegate.tsx:170-183` compares them against `amount`, which is the human-readable LPT input:
```js
const sufficientBalance = Number(tokenBalance) >= amount; // 1.4e19 >= 5
const sufficientTransferAllowance = Number(transferAllowance) >= amount; // 1.1e17 >= 5
```
Both are true for any realistic input, so:
1. `showApproveFlow` (`:186`) is false whenever allowance is non-zero, and the Approve/Delegate pair is never shown.
2. `useSimulateContract` for `bondWithHint` (`:136`) reverts on the real ERC-20 allowance check, leaving `bondWithHintConfig` undefined.
3. `onDelegate` (`:206-214`) throws `No config for bond with hint` into `catch { console.error(e) }`, so the click is a no-op.
`sufficientBalance` is broken the same way, so the "Insufficient Balance" guard at `:228` can never fire either.
## Why it went unnoticed
Only wallets with a *partial non-zero* allowance are affected. With allowance exactly `0`, `Number(transferAllowance) > 0` is false, the approve flow shows correctly, and the explorer grants `MAX_UINT256` — so the normal path never hits this. Users land in the broken state when a wallet (Rabby, MetaMask) overrides the unlimited approval with an exact amount.
`InputBox.tsx:51` correctly applies `fromWei` for display, which is why the balance shown is right while the comparison is wrong.
## Introduced
`989c09b` (2022-08-31, #165). Before that commit, `Footer.tsx` passed formatted values:
```js
const tokenBalance = account && parseFloat(Utils.fromWei(account.tokenBalance));
const transferAllowance = account && parseFloat(Utils.fromWei(account.allowance));
```
#165 switched them to the raw wei values from the new `/api/account-balance` route without reintroducing `fromWei`, leaving the comparisons unchanged.
## Proposed fix
Compare in wei using BigInt:
```js
const amountWei = useMemo(() => {
try {
return amount ? parseEther(amount) : 0n;
} catch {
return 0n;
}
}, [amount]);
const sufficientBalance = useMemo(
() => amountWei > 0n && BigInt(tokenBalance ?? 0) >= amountWei,
[amountWei, tokenBalance]
);
const sufficientTransferAllowance = useMemo(
() => amountWei > 0n && BigInt(transferAllowance ?? 0) >= amountWei,
[amountWei, transferAllowance]
);
```
Also disable the Delegate button while `bondWithHintConfig` is undefined (or surface the error) so a failed simulation can never present as a working button.
## Workaround
Set the allowance to `0` (wallet or revoke.cash); the approve flow then reappears and grants unlimited approval correctly.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with components/DelegatingWidget/Delegate.tsx:136, 170-183, 186, 206-214, and 228, then inspect pages/api/account-balance/[address].tsx:44-47 and InputBox.tsx:51. Verify the balance and allowance comparisons use the raw wei values consistently, and check the partial-allowance path. Done means partial allowances show the approval flow or a clear error, sufficient amounts can delegate, and insufficient balances are rejected without a silent no-op.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- blockchain, frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100