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:
const sufficientBalance = Number(tokenBalance) >= amount; // 1.4e19 >= 5
const sufficientTransferAllowance = Number(transferAllowance) >= amount; // 1.1e17 >= 5
Both are true for any realistic input, so:
showApproveFlow (:186) is false whenever allowance is non-zero, and the Approve/Delegate pair is never shown.
useSimulateContract for bondWithHint (:136) reverts on the real ERC-20 allowance check, leaving bondWithHintConfig undefined.
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:
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:
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.
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-balancereturnsbalanceandallowanceas raw wei strings (pages/api/account-balance/[address].tsx:44-47), butcomponents/DelegatingWidget/Delegate.tsx:170-183compares them againstamount, which is the human-readable LPT input:Both are true for any realistic input, so:
showApproveFlow(:186) is false whenever allowance is non-zero, and the Approve/Delegate pair is never shown.useSimulateContractforbondWithHint(:136) reverts on the real ERC-20 allowance check, leavingbondWithHintConfigundefined.onDelegate(:206-214) throwsNo config for bond with hintintocatch { console.error(e) }, so the click is a no-op.sufficientBalanceis broken the same way, so the "Insufficient Balance" guard at:228can never fire either.Why it went unnoticed
Only wallets with a partial non-zero allowance are affected. With allowance exactly
0,Number(transferAllowance) > 0is false, the approve flow shows correctly, and the explorer grantsMAX_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:51correctly appliesfromWeifor display, which is why the balance shown is right while the comparison is wrong.Introduced
989c09b(2022-08-31, #165). Before that commit,Footer.tsxpassed formatted values:#165 switched them to the raw wei values from the new
/api/account-balanceroute without reintroducingfromWei, leaving the comparisons unchanged.Proposed fix
Compare in wei using BigInt:
Also disable the Delegate button while
bondWithHintConfigis 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.