7

I'm trying to use web3 to transfer all (or as much as I can) of the balance of an account to another account. Here is the code I have so far:

var sender = web3.eth.accounts[0];
var receiver = web3.eth.accounts[1];
var totalBalance = web3.eth.getBalance(sender);
var valueToSend = totalBalance;

transactionObject = {
  from: sender,
  to: receiver,
  value: valueToSend
} 

web3.eth.sendTransaction(transactionObject);

However I know that the previous code has the following problem:

  • The total balance can not be sent because there wouldn't be enough residual ether to be used as gas for the transaction.

I saw another post make the following recommendation:

  • subtract the totalBalance by gas*price, hence:

    valueToSend = totalBalance - (gas*price);
    

QUESTION / PROBLEM:

but the problem I am having here is how would that look in code? I don't know how to obtain the current price in code. And for the gas, I understand that there are different values for gas depending on how fast you want a transaction to go, but is there web3 code that defines the least and most you can use? Or is there a graph somewhere that defines it online? And how would that look in code?

4

If you are sending to an address that is not a contract the gas is always 21000.

For a contract you can estimate with web3.eth.estimateGas. It calculates the gas executing the contract locally, so when the transaction is mined the result can be different, usually you add an extra to make sure it will work.

But I think Ethereum developers are aware of the problem of leaving an account with too few ether to make a new transfer, there were discussion who can pay for the gas.

To determine the gas price to use you can try web3.eth.gasPrice, from the documentation

This property is read only and returns the current gas price. The gas price is determined by the x latest blocks median gas price.

How the value is determined is not documented. For a more detailed analysis you can check ethgasstation.info, the site does not appear to provide an api.

  • thanks for the feedback. the explanations really helped. I am getting closer and closer to manage to do my first transaction, how I'm having another issue. If you happen to know the solution to this one: ethereum.stackexchange.com/questions/19329/… I would be eternally grateful :) – Webeng Jul 3 '17 at 17:56
3

You could estimate the gas by using web3.eth.estimateGas to get an estimate of gas used by your transactions and then you can subtract the estimated gas from total balance to get you valueTosend.

transactionObject = {
  from: sender,
  to: receiver,
  value: totalBalance
} 

var estimatedGas= eth.estimateGas(transactionObject);
web3.eth.getGasPrice(function(error, result){
  gasPrice = result.toNumber();
  var gasValue = estimatedGas * gasPrice
  var valueToSend = totalBalance - gasValue;   
  });

Also, just to mention, you can specify gasPrice of your choice by using gasPrice in config. However, it's better if you don't alter the default gas. Also if you are sending eth to EOA, gas is always 21000, so you can replace estimatedGas with const 21000.

  • 1
    Thank you for the explanation and code man! I wish I could give both you and Ismael the check mark :( – Webeng Jul 3 '17 at 17:57
  • wait, doesn't the estimatedGas need to be multiplied by the price of the Gas? – Webeng Jul 4 '17 at 2:33
  • Thanks for pointing out. I missed it, my bad. I have updated the answer. – Prashant Prabhakar Singh Jul 4 '17 at 20:28
  • This is not working 100% of the time. Not working at all for me now. All the calculations are correct and I still get the "insufficient funds for gas * price + value" error. It seems like I need to add an extra epsilon ether value that would be left on the sending account so I can't completely empty an account. If I'm wrong please correct me. – androidu Jun 18 '18 at 10:17
  • This should work. Just be sure, you send same gas and gas price to send tx that you used to estimate the value to send. – Prashant Prabhakar Singh Jun 18 '18 at 10:34
1

Sending To A Regular Account

This solution is for sending the entire balance of an account to another regular account (not a contract account), where the gas is always 21,000.

The important part in the answer below is to use BigNumber mathematics, or you will sometimes end up with incorrect numbers and your transaction will be rejected, or you will be left with some remaining gas in your originating account.

var from = {from account};
var to = {to account};
var balance = eth.getBalance(from);
var gas = new BigNumber(21000);
// You can use gasPrice=web3.eth.gasPrice or look up http://ethgasstation.info/
var gasPrice = web3.toWei(1, "gwei");
var cost = gas.mul(gasPrice);
var sendAmount = balance.sub(cost);
var tx = eth.sendTransaction({from: from, to: to, gas: gas, gasPrice: gasPrice, value: sendAmount});
eth.getTransaction(tx);


Sending To A Contract Account

If you are trying to send the entire balance from an account to a contract account, the problem gets much harder as the estimated gas (using web3.eth.estimateGas(...)) will seldom be the actual gas used.



BigNumber Calculations

Sample Incorrect Calculation

And example of some incorrect calculations, when BigNumber mathematics is not used:

// eth.getBalance(...) returns BigNumber. Number simulated in this case
> balance=new BigNumber(49999979000000000000);
49999979000000000000
> balance
49999979000000000000
> gas=21000
21000
> gasPrice=web3.toWei(1, "gwei");
"1000000000"
> cost=gas*gasPrice;
21000000000000
> cost
21000000000000
> incorrectSendAmount=balance-cost
49999958000000010000
> balance-incorrectSendAmount
20999999995904
// Small error in the calculations
> balance-incorrectSendAmount-cost
-4096

Sample Correct Calculation

And the same calculations when using BigNumber mathematics:

// eth.getBalance(...) returns BigNumber. Number simulated in this case
> balance=new BigNumber(49999979000000000000);
49999979000000000000
> balance
49999979000000000000
> gas=new BigNumber(21000)
21000
> cost=gas.mul(gasPrice);
21000000000000
> correctSendAmount=balance.sub(cost);
49999958000000000000
// No errors in the calculations
> balance.sub(correctSendAmount).sub(cost)
0

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.