livepeer / livepeer/explorer

fix: Delegate button silently fails when LPT allowance is partially approved

Open
#737 1 comment 0 reactions 0 assignees View on GitHub

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.