1

On BSC, usually when your transaction to a contract fails such a tx uses about 30k gas when you do it through a wallet. But when a transaction made with an ethers.js script fails, it uses all the gas up to the gasLimit. Is there anything I can do to make my script behave correctly?

What should be: https://bscscan.com/tx/0xb36a1ae9d8294db8e1e1faf23c5c8d98d5e1cbcf3ae3bd57dc7f1fcb648b9041

What happens: https://bscscan.com/tx/0x864e489c1e678d536b07d84bccd609d07002d6d1a66a6a0ff2a368ab53bc47eb

const ethers = require("ethers");

const purchaseAmount = ethers.utils.parseEther("1");
const recepient = "";

const privateKey = "";

const sender = "";

const provider = new ethers.providers.WebSocketProvider("wss://bsc-ws-node.nariox.org:443");

const wallet = new ethers.Wallet(privateKey, provider);

const Tx = require('ethereumjs-tx')

async function sendEths() {

  let txCount = await provider.getTransactionCount(sender);
  
   let tx = {
    nonce: ethers.utils.hexlify(txCount),
    to: recepient,
    value: purchaseAmount,
    gasLimit: 140000,
    gasPrice: ethers.utils.parseUnits("5", "gwei"),
  };

  console.log("Sending transactions");

  let receipt = await wallet.sendTransaction(tx);

  console.log("Transaction receipt");

  console.log(receipt);
  process.exit();
};

sendEths();
2
  • That'a a bit puzzling because these tx have no input data but yet behave differently... Are you the owner of both the addresses that sent the tx that you linked? Do you have the contract source code?
    – Undead8
    Commented Jul 9, 2021 at 23:14
  • Do you have the contract source code? The developers have control how to deal with errors. One way to deal with these errors is to call estimateGas if it fails then it is likely the transaction will also fail.
    – Ismael
    Commented Jul 10, 2021 at 4:37

2 Answers 2

2

Regular transaction revertion only eats up gas until the revertion happens, and return the rest.

If an invalid opcode happens, all of the gas is eaten. Basically an invalid opcode happens only if the contract does something it shouldn't do, such as dividing by zero. So it's typically a serious developer bug. If I remember right, the gas is eaten as a sort of a punishment: the transaction execution really shouldn't end up into an invalid opcode and eating the gas should tell users that something is not right with the contract.

0

This actually, is called robbery. It is programmed in the sources, if your transaction fails, instead of consuming what you have so far consumed, the EVM will eat up your full gas limit even if you consumed 1 gas unit after the initial 21,000 . There is nothing you can do because this robbery is programmed within the sources of Ethereum:

if err != nil {
    evm.StateDB.RevertToSnapshot(snapshot)
    if err != ErrExecutionReverted {
        gas = 0
    }
    // TODO: consider clearing up unused snapshots:
    //} else {
    //  evm.StateDB.DiscardSnapshot(snapshot)
}

https://github.com/ethereum/go-ethereum/blob/9624f92edef5e0a76a97efd302e983077acb6e35/core/vm/evm.go#L224:L232

Shame on you, Vitalik Buterin.

If you want it to "behave correctly" as you say, just issue "REVERT" opcode at the end, because this is the condition that will decide either eat up your gas or not:

if err != ErrExecutionReverted {
    gas = 0
}

it will eat up if you have error different than revert, and thats exactly what you observe in Etherscan, Invalid opcode is not a REVERT-able exit status.

1
  • I would prefer a bit more objective answers. Your answer is quite opinionated and it's a bit funny how you blame Vitalik for some Solidity implementation (Geth) - I doubt he himself wrote a single line of Geth code. Commented May 24, 2022 at 12:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.