fix: sign the ERC-20 amount the confirmation screen displayed (closes #305)
The send screen was built from the indexer's decimals while the transfer was encoded from the contract's decimals() read at signing time, with nothing comparing them. A token whose scales disagree moved 10^12 times the approved amount. The displayed scale is now carried on pendingTx from the same tokenBalances entry the amount, balance and symbol were rendered from, and both encode sites use it. transferAmount.js refuses rather than falling back when the two scales disagree or either is unusable. Adds the first end-to-end coverage of the popup's own Send -> ConfirmTx -> Sign & Send path; #btn-confirm-send had never been clicked by any test.
This commit was merged in pull request #314.
This commit is contained in:
@@ -25,6 +25,10 @@ const {
|
||||
getFullWarnings,
|
||||
} = require("../../shared/addressWarnings");
|
||||
const { ERC20_ABI, isBurnAddress } = require("../../shared/constants");
|
||||
const {
|
||||
displayedDecimals,
|
||||
transferAmountUnits,
|
||||
} = require("../../shared/transferAmount");
|
||||
const {
|
||||
CODES,
|
||||
FEE_PENDING,
|
||||
@@ -302,8 +306,17 @@ async function estimateGas(txInfo) {
|
||||
});
|
||||
} else {
|
||||
const contract = new Contract(txInfo.token, ERC20_ABI, provider);
|
||||
const decimals = await contract.decimals();
|
||||
const amount = parseUnits(txInfo.amount, decimals);
|
||||
// The scale the screen is rendering with, not the contract's own
|
||||
// answer: the estimate has to be for the transfer that would be
|
||||
// signed, and that one is encoded from what was displayed. See
|
||||
// transferAmount.js. A pending transaction that carries no usable
|
||||
// scale throws here, which reports the fee as unknown and leaves
|
||||
// Send blocked — an amount that cannot be checked against the
|
||||
// screen is never estimated for, let alone sent.
|
||||
const amount = parseUnits(
|
||||
txInfo.amount,
|
||||
displayedDecimals(txInfo.tokenDecimals),
|
||||
);
|
||||
gasLimit = await contract.transfer.estimateGas(txInfo.to, amount, {
|
||||
from: txInfo.from,
|
||||
});
|
||||
@@ -445,8 +458,16 @@ function init(_ctx) {
|
||||
ERC20_ABI,
|
||||
connectedSigner,
|
||||
);
|
||||
const decimals = await contract.decimals();
|
||||
const amount = parseUnits(pendingTx.amount, decimals);
|
||||
// The contract's decimals() is read to be COMPARED with the
|
||||
// scale the screen rendered this amount at, not to encode with:
|
||||
// encoding from it signs whatever the contract answers now,
|
||||
// which is not what the user read. A disagreement throws and is
|
||||
// reported on the error screen. See transferAmount.js.
|
||||
const amount = transferAmountUnits(
|
||||
pendingTx.amount,
|
||||
pendingTx.tokenDecimals,
|
||||
await contract.decimals(),
|
||||
);
|
||||
tx = await contract.transfer(pendingTx.to, amount);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user