5

I am running go-ethereum that has x amount of ether, i want to distribute some ether to friends.

Rather than 5 seperate transactions:

eth.sendTransaction({from: eth.accounts[0], to: "0xxxxxxxxxxxxxxxxxxxxxxxxx1", value: web3.toWei(1, "ether")})
eth.sendTransaction({from: eth.accounts[0], to: "0xxxxxxxxxxxxxxxxxxxxxxxxx2", value: web3.toWei(1, "ether")})
eth.sendTransaction({from: eth.accounts[0], to: "0xxxxxxxxxxxxxxxxxxxxxxxxx3", value: web3.toWei(1, "ether")})
eth.sendTransaction({from: eth.accounts[0], to: "0xxxxxxxxxxxxxxxxxxxxxxxxx4", value: web3.toWei(1, "ether")})
eth.sendTransaction({from: eth.accounts[0], to: "0xxxxxxxxxxxxxxxxxxxxxxxxx5", value: web3.toWei(1, "ether")})

Can i somehow send to multiple addresses in a single transaction? I'm trying to reduce fees.

4 Answers 4

3

You can create a smart contract that has a method for sending ether to multiple accounts:

pragma solidity ^0.4.13;


contract BulkSender {

    /// @notice Send the specified amounts of wei to the specified addresses
    /// @param addresses Addresses to which to send wei
    /// @param amounts Amounts for the corresponding addresses, the size of the
    /// array must be equal to the size of the addresses array
    function bulkSend(address[] addresses, uint256[] amounts) public payable {
        require(addresses.length > 0);
        require(addresses.length == amounts.length);

        uint256 length = addresses.length;
        uint256 currentSum = 0;
        for (uint256 i = 0; i < length; i++) {
            uint256 amount = amounts[i];
            require(amount > 0);
            currentSum += amount;
            require(currentSum <= msg.value);
            // Costs 9700 gas for existing accounts, 
            // 34700 gas for nonexistent accounts.
            // Might fail in case the destination is a smart contract with a default
            // method that uses more than 2300 gas.
            // If it fails the top level transaction will be reverted.
            addresses[i].transfer(amount);
        }
        require(currentSum == msg.value);
    }
}

However it might cost you more or less than sending transactions separately depending on whether destination accounts are existing accounts (e.g. already have a non-zero balance) or new accounts.

As explained on the Subtleties page in Ethereum's wiki:

CALL has a multi-part gas cost:

  • 700 base
  • 9000 additional if the value is nonzero
  • 25000 additional if the destination account does not yet exist (note: there is a difference between zero-balance and nonexistent!)

You can see from this trace for the first CALL (nonexistent account) the gas price is 34700, for the second CALL (existing account) the gas price is 9700.

So for an existing account you'd save roughly 11300 (21000 - 9700) gas, but for a new account you would waste 13700 (34700 - 21000) gas.

0

There is no way to avoid fees of a transfer, other than adjusting the gasPrice. You could bring the gasPrice down to a very low amount(possibly even zero) and it will still get processed, albeit slowly. So using your example:

eth.sendTransaction({from: eth.accounts[0], to: "0xxxxxxxxxxxxxxxxxxxxxxxxx1", value: web3.toWei(1, "ether"), gasPrice: 10})

Alternatively, you could potentially shift most of the cost onto your friends, by creating a contract that they then request the funds from. However, this doesn't reduce cost, it just shifts the burden onto your friends.

I hope someone here will correct me if I'm wrong.

4
  • Are you sure? Transfer value is 9000 - what are the other costs that add up to 21000 if you have a single contract do a bunch of transfers? ethereum.github.io/yellowpaper/paper.pdf Sep 6, 2017 at 11:43
  • @EdmundEdgar I don't understand your question. Sep 6, 2017 at 16:55
  • So I'm thinking if you did a simple send to a contract with a list of 100 addresses, and contract did the transfer to the 100 accounts, it's all one transaction, so the 21000 gas base only applies once. That way you pay for each transfer, which is 9000 per address, plus assorted gubbins like the cost of the data taken by the address in the transaction data, which sounds like it would be less than 21000 per address. Haven't tried it though. Sep 6, 2017 at 20:53
  • @EdmundEdgar I believe that is incorrect. It would end up being n+1 transfers adding up the gas. Contract instructions(including transfers) all cost gas. If your destination addresses requested the transfer, however, the fee liability would be transferred to the recipient. Sep 7, 2017 at 0:21
0

I haven't tried this on an actual network but you should be able to do something like this:

pragma solidity ^0.4.13;

contract BulkSender {

    function bulkSend(address[] addrs) payable {
        uint256 l = addrs.length;
        uint256 i;
        for(i=0; i<l; i++) {
            // Rounds down, you should lose a wei or two
            // If one of these throws an exception the whole thing will revert
            // ...and you'll have to try again omitting the deadbeat
            addrs[i].transfer(msg.value/l);
        }
    }

}

Pyethereum tells me that costs 94294 gas for 8 addresses, whereas a single simple send would normally be 21000 * 8 = 168000. I think there may be a bit more overhead in there that pyethereum isn't catching (maybe the transaction data part?), but it seems to work out cheaper.

I haven't heard of people doing this, so I'd be interested to hear if there's a reason why they don't, or if I'm getting the gas price calculation wrong somehow.

1
  • The reason people are not doing this I guess is because the CALL opcode price is 34700 for the new account and 9700 for existing account. In most cases people need to send ether to new accounts so the contract way costs more than a direct transaction. You can see my answer for details. Nov 9, 2017 at 13:04
0

the more number of steps in smart contract the more cost would be. so somehow we can adjust the gas price it could be less or more than the combined gas. for info please prefer https://github.com/ethereum/wiki/wiki/Subtleties

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.