5

I have an Ethereum account loaded with Ethers and I need to spend all of them, leaving account final balance at exactly zero Weis. Is that possible?

I know using method eth_estimateGas() and multiplying by gasPrice it computes txCost, but is really there any guarantee this will be the actual fee of my next transaction? Gas estimation could change according to https://github.com/ethereum/go-ethereum/issues/2395 and gas price is not fixed, nor predictable https://etherscan.io/charts/gasprice

Is there any way to perform a transaction knowing exactly the final balance of sender prior to sending it?

  • 1
    You "need" to leave exactly zero wei behind? Why? – Nick Johnson Sep 13 '16 at 8:07
  • Just adding up a fiat accounting that's been audited through blockchain. When a user performs a payout, balance drops to zero. – Juan Ignacio Pérez Sacristán Sep 13 '16 at 11:11
  • That doesn't seem like it would have to leave a balance of exactly zero. A few hundred gas, at current gas prices, works out to a tiny fraction of a penny. – Nick Johnson Sep 14 '16 at 12:12
4

Yes if you are transferring to an Externally Owned Account (EOA).

No if you are transferring to a contract account.

You can specify the gasPrice (x gas) you are willing to pay for your transaction and the miner will decide whether to mine your transaction.

For an EOA, the gas is always 21000, so you can specify the fee exactly.

For a contract account, estimateGas(...) will not always return the exact gas required to execute your transaction (see What are the limitations to estimateGas and when would its estimate be considerably wrong?), so you cannot specify the fee exactly.

From Gas and transaction costs:

Gas limit is there to protect you from buggy code running until your funds are depleted. The product of gasPrice and gas represents the maximum amount of Wei that you are willing to pay for executing the transaction. What you specify as gasPrice is used by miners to rank transactions for inclusion in the blockchain. It is the price in Wei of one unit of gas, in which VM operations are priced.

Here's an example:

> eth.gasPrice
20000000000

// Specify a lower gasPrice
> eth.sendTransaction({from: eth.accounts[1], to: eth.accounts[2], gasPrice: 15000000000, value: web3.toWei(1, "ether")});
"0x9e53cb0268ae6b75303c46a20d869e2a6f95a93269a5c07bf5bf1f37ff6fea80"

The transaction is mined. The transaction receipt shows gas used 21000:

> eth.getTransactionReceipt("0x9e53cb0268ae6b75303c46a20d869e2a6f95a93269a5c07bf5bf1f37ff6fea80");
{
  blockHash: "0xd0bd16c0a3064a5ee1d45762030080b1791d14ec80504f01c839577881696e60",
  blockNumber: 5706,
  contractAddress: "0x39236bc7d128340b345138d997854981eb4948e7",
  cumulativeGasUsed: 21000,
  from: "0x4d5bbe7fbc80933ffa90ece988a764e41ee6d018",
  gasUsed: 21000,
  logs: [],
  root: "86edc80b49786b7dc101c54f85659715661121a22e36dcfd90bf2c0961142493",
  to: null,
  transactionHash: "0x9e53cb0268ae6b75303c46a20d869e2a6f95a93269a5c07bf5bf1f37ff6fea80",
  transactionIndex: 0
}

And the gasPrice is 15000000000 as specified in the transaction:

> eth.getTransaction("0x9e53cb0268ae6b75303c46a20d869e2a6f95a93269a5c07bf5bf1f37ff6fea80");
{
  blockHash: "0xd0bd16c0a3064a5ee1d45762030080b1791d14ec80504f01c839577881696e60",
  blockNumber: 5706,
  from: "0x4d5bbe7fbc80933ffa90ece988a764e41ee6d018",
  gas: 90000,
  gasPrice: 15000000000,
  hash: "0x9e53cb0268ae6b75303c46a20d869e2a6f95a93269a5c07bf5bf1f37ff6fea80",
  input: "0x",
  nonce: 6,
  to: null,
  transactionIndex: 0,
  value: 1000000000000000000
}

Check the miner's account in the block before the mined transaction and at the block when the transaction was mined:

> web3.fromWei(eth.getBalance(eth.accounts[0], 5705),"ether")
28522.81130279    
> web3.fromWei(eth.getBalance(eth.accounts[0], 5706),"ether")
28527.81161779

And here's the difference which shows the 5 ETH mining reward + the transaction fees collected:

> web3.fromWei(eth.getBalance(eth.accounts[0], 5706).minus(eth.getBalance(eth.accounts[0], 5705)),"wei")
5000315000000000000

And confirming that the transaction fees earned is gas x specified gasPrice:

> new BigNumber(21000).times(15000000000)
315000000000000



And this leads to the next question, what happens when you specify a gasPrice higher than the current gasPrice?

So here is the same information with the specified gasPrice higher than the current gasPrice:

> eth.sendTransaction({from: eth.accounts[1], to: eth.accounts[2], gasPrice: 25000000000, value: web3.toWei(1, "ether")});    
"0xcbd2a112c77baeca47550f49181fd2fcb05b3551b71f6180a30a55672c6aab3d"

The transaction receipt:

> eth.getTransactionReceipt("0xcbd2a112c77baeca47550f49181fd2fcb05b3551b71f6180a30a55672c6aab3d")
{
  blockHash: "0x58ba7819f778f482930e67a2914c0174aaf92bfb680b407fa9bcd55cfe5e4e80",
  blockNumber: 5808,
  contractAddress: "0xc5c9b0194bb6184db6a278f96525718a45d310a5",
  cumulativeGasUsed: 21000,
  from: "0x4d5bbe7fbc80933ffa90ece988a764e41ee6d018",
  gasUsed: 21000,
  logs: [],
  root: "68774aad53457e6cd4cd3b9344235e43a021366ff9763156224dbf07101b55af",
  to: null,
  transactionHash: "0xcbd2a112c77baeca47550f49181fd2fcb05b3551b71f6180a30a55672c6aab3d",
  transactionIndex: 0
}

The transaction details:

> eth.getTransaction("0xcbd2a112c77baeca47550f49181fd2fcb05b3551b71f6180a30a55672c6aab3d")
{
  blockHash: "0x58ba7819f778f482930e67a2914c0174aaf92bfb680b407fa9bcd55cfe5e4e80",
  blockNumber: 5808,
  from: "0x4d5bbe7fbc80933ffa90ece988a764e41ee6d018",
  gas: 90000,
  gasPrice: 25000000000,
  hash: "0xcbd2a112c77baeca47550f49181fd2fcb05b3551b71f6180a30a55672c6aab3d",
  input: "0x",
  nonce: 7,
  to: null,
  transactionIndex: 0,
  value: 1000000000000000000
}

The change in balance shows that the miner will use your specified gasPrice and pocket the higher transaction fees:

> web3.fromWei(eth.getBalance(eth.accounts[0], 5808).minus(eth.getBalance(eth.accounts[0], 5807)),"wei")
5000525000000000000

Confirming that the transaction used your specified gasPrice:

> new BigNumber(21000).times(25000000000)
525000000000000
  • Perfect explanation, thx a lot. Just a doubt: If eth.gasPrice is 20000000000 how is it possible that Ethereum accepts first transaction with a lower gasPrice: 15000000000 ? – Juan Ignacio Pérez Sacristán Sep 12 '16 at 23:12
  • 2
    Actually, it is possible to send an exact amount of gas to a contract, in more ways than one. First, since Ethereum is totally deterministic, it is possible, with quite a bit of effort, to exactly know how much gas a transaction will use in many cases. Second, it is possible to construct a contract that is guaranteed to consume almost all gas that you send it. You just use a low-level call to carry out the actual tx, then waste the rest of the gas. This can get you to under 6 gas left over, which is frankly nothing. – Tjaden Hess Sep 12 '16 at 23:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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