fix: estimate a request even when the site sends its gas limit (closes #554)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run

ethers asks the node for a gas estimate only when the request has no gas
limit, and that estimate is the wallet's only check that a transaction
does not revert. Since a site's `gas` became the gas limit, a reverting
request carrying one opened the approval window and could be signed and
mined to fail. Such a request is now estimated first, with the site's
limit and under the same timeout; a failure goes back to the site with no
window, and the site's gas limit is still the one shown and signed. A
limit too low for the call now fails the same way.

Model: opus-5-5
This commit was merged in pull request #557.
This commit is contained in:
2026-10-14 19:46:01 +02:00
parent c40c7432a5
commit 575f1658ae
3 changed files with 65 additions and 8 deletions
+14 -3
View File
@@ -201,6 +201,7 @@ async function prepareApprovalTx(provider, from, txParams) {
throw fail("There is no active address to send this transaction from.");
}
const request = requestFrom(txParams || {}, from);
const signer = new VoidSigner(getAddress(from), provider);
let populated;
try {
@@ -208,10 +209,20 @@ async function prepareApprovalTx(provider, from, txParams) {
// nonce, gas, fee and chain id are populated exactly as they were when
// the popup did this. VoidSigner cannot sign, which is the point: the
// background prepares, the popup signs.
//
// ethers asks the node for a gas estimate only when the request has
// no gas limit, and that estimate is the only check that the
// transaction does not revert. So a request carrying the site's gas
// limit is estimated first, with that limit: one that reverts, or
// needs more gas than the site gave it, fails here as well. The
// site's gas limit is still the one populated.
populated = await withTimeout(
new VoidSigner(getAddress(from), provider).populateTransaction(
request,
),
(async () => {
if (present(request.gasLimit)) {
await signer.estimateGas(request);
}
return signer.populateTransaction(request);
})(),
POPULATE_TIMEOUT_MS,
"The transaction could not be prepared: the network did not answer in time.",
);