Multi Send ETH (Contract)


This contract is useful when you want to save gas to send ETH to multiple recipient. There are 2 ways to execute, one is send based on right in ETH value, another way is send from contract's ETH balance.


Few things worth to take note:

  • Gas used send to new address (or any zero ETH balance address) is higher than address with ETH balance.
  • The more the recipient, the cheaper the cost per ETH transfer as in compare to normal send which consume 21,000 gas.
  • If transfer ETH to 1 recipient only , then apparently gas cost is expensive than normal send ETH.

<?Php
$abi = '[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"getEthBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"multiSendDiffEth","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"multiSendDiffEthFromContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable[]","name":"recipients","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"multiSendFixedEth","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable[]","name":"recipients","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"multiSendFixedEthFromContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]';

$bytecode = "608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610b4d806100606000396000f3fe60806040526004361061007b5760003560e01c8063893d20e81161004e578063893d20e8146102605780638da5cb5b146102b75780639749c04a1461030e578063eaeb15df1461045a5761007b565b806331a933911461008d578063390430361461014f5780633ccfd60b1461021e57806370ed0ada14610235575b6000803690501461008b57600080fd5b005b61014d600480360360408110156100a357600080fd5b81019080803590602001906401000000008111156100c057600080fd5b8201836020820111156100d257600080fd5b803590602001918460208302840111640100000000831117156100f457600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050509192919290803590602001909291905050506105b3565b005b34801561015b57600080fd5b5061021c6004803603604081101561017257600080fd5b810190808035906020019064010000000081111561018f57600080fd5b8201836020820111156101a157600080fd5b803590602001918460208302840111640100000000831117156101c357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019092919050505061065e565b005b34801561022a57600080fd5b50610233610763565b005b34801561024157600080fd5b5061024a610805565b6040518082815260200191505060405180910390f35b34801561026c57600080fd5b5061027561080d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156102c357600080fd5b506102cc610836565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6104586004803603604081101561032457600080fd5b810190808035906020019064010000000081111561034157600080fd5b82018360208201111561035357600080fd5b8035906020019184602083028401116401000000008311171561037557600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050509192919290803590602001906401000000008111156103d557600080fd5b8201836020820111156103e757600080fd5b8035906020019184602083028401116401000000008311171561040957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929050505061085b565b005b34801561046657600080fd5b506105b16004803603604081101561047d57600080fd5b810190808035906020019064010000000081111561049a57600080fd5b8201836020820111156104ac57600080fd5b803590602001918460208302840111640100000000831117156104ce57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561052e57600080fd5b82018360208201111561054057600080fd5b8035906020019184602083028401116401000000008311171561056257600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050509192919290505050610946565b005b60008251116105c157600080fd5b600081116105ce57600080fd5b3481835102146105dd57600080fd5b60008251905060008090505b81811015610658578381815181106105fd57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561064a573d6000803e3d6000fd5b5080806001019150506105e9565b50505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106b757600080fd5b60008251116106c557600080fd5b600081116106d257600080fd5b478183510211156106e257600080fd5b60008251905060008090505b8181101561075d5783818151811061070257fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561074f573d6000803e3d6000fd5b5080806001019150506106ee565b50505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146107bc57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015610802573d6000803e3d6000fd5b50565b600047905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600082511161086957600080fd5b805182511461087757600080fd5b600082519050600080905060008090505b8281101561093f57600084828151811061089e57fe5b60200260200101519050600081116108b557600080fd5b6108c88184610a9090919063ffffffff16565b9250348311156108d757600080fd5b8582815181106108e357fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610930573d6000803e3d6000fd5b50508080600101915050610888565b5050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461099f57600080fd5b60008251116109ad57600080fd5b80518251146109bb57600080fd5b6000825190506000809050600047905060008090505b83811015610a885760008582815181106109e757fe5b60200260200101519050600081116109fe57600080fd5b610a118185610a9090919063ffffffff16565b935082841115610a2057600080fd5b868281518110610a2c57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610a79573d6000803e3d6000fd5b505080806001019150506109d1565b505050505050565b600080828401905083811015610b0e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b809150509291505056fea265627a7a72315820ac6172173b7ecde67c3fbf5d0b36985128e0d511b9f1698f1471990324830cd664736f6c63430005110032";
?>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
		<meta name="description" content="">
		<meta name="author" content="">
		<meta name="keywords" content="<?php echo $_HTML['meta']['keywords']?>">
		<title><?php echo $_HTML['title']?></title>
		
		<script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js@1.0.0-beta.34/dist/web3.min.js"></script>
		<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ethjs@0.3.4/dist/ethjs.min.js"></script>
		<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ethjs-contract@0.2.3/dist/ethjs-contract.min.js"></script>
		
		<!-- Bootstrap core CSS -->
		<link href="../media/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
		<link href="../media/vendor/enlighter/css/enlighterjs.min.css?<?php echo time()?>" rel="stylesheet">
		<!-- Custom styles for this template -->
		<link href="../media/css/simple-sidebar.css?<?php echo time()?>" rel="stylesheet">
		<!-- Bootstrap core JavaScript -->
		<script src="../media/vendor/jquery/jquery.min.js"></script>
		
	</head>
	<body>
		<div class="d-flex" id="wrapper">
		<!-- Page Content -->
			<div id="page-content-wrapper" >
				<p>
					<h6 class="mt-3">Experiment</h6>
					<ul>
						<li>Contract deployment <a target="_blank" href="https://ropsten.etherscan.io/address/0x4e58bd0521716a2da492165d58d83580190b9725"><img style='width:12px;height:12px;' src='../media/images/external_link.png'/></a>
						</li>
						<li>
							&#10004; Call multiSendFixedEth with input of 2 <b>addresses with ETH balance</b> <a target="_blank" href="https://ropsten.etherscan.io/tx/0x6c7952906daa4212c4b4dcf0ac3df661471ceb66f52bdd8f6aa068336ae48f8c"><img style='width:12px;height:12px;' src='../media/images/external_link.png'/></a>. Gas consumed 39,481, with 19,740.5 gas per ETH transfer.
						</li>
						<li>
							&#10006; Call multiSendFixedEth with input of 2 <b>zero ETH balance address</b> <a target="_blank" href="https://ropsten.etherscan.io/tx/0x1e6085f4cd6681b68e7789f81ef011e8cb322db4781184f845f25758b6385fea"><img style='width:12px;height:12px;' src='../media/images/external_link.png'/></a>. Gas consumed 91,981, with 45,990.5 gas per ETH transfer.
						
						</li>
					</ul>
				</p>
				<p>
					<h6 class="mt-3">ABI</h6>
					<textarea class="form-control" rows="5" id="comment" readonly><?php echo $abi;?></textarea>
				</p>
				<p>
					<h6 class="mt-3">Bytecode</h6>
					<textarea class="form-control" rows="5" id="comment" readonly><?php echo $bytecode;?></textarea>
				</p>
				<p>
					<button id="deploy-contract" class="btn btn-primary">Deploy Contract</button> Via Meta Mask <b> OR </b> <a href="eth_sc_deploy_contract.php?data=<?php echo $bytecode?>&disable_fields=data,to" target="_parent">Use Manual Way</a>
				</p>
				<script>

				try {
					
					// the abi
					const contractABI = JSON.parse('<?php echo $abi?>');

					// bytecode
					const contractBytecode = '<?php echo $bytecode?>';

					var button = document.querySelector('button#deploy-contract');
					
					button.addEventListener('click', async (e) => {
						
						e.srcElement.innerHTML = "Check Connection ...";
						// Modern dapp browsers...
						if (window.ethereum) {
							window.web3 = new Web3(ethereum);
							try {
								// Request account access if needed
								await ethereum.enable();
								e.srcElement.innerHTML = "Deploy Contract";
								// Modern dapp browsers...
								// Acccounts now exposed
								startApp(window.web3);
							} catch (error) {
								e.srcElement.innerHTML = "Deploy Contract";
								// User denied account access...
							}
						}
						// Legacy dapp browsers...
						else if (window.web3) {
							window.web3 = new Web3(web3.currentProvider);
							// Acccounts always exposed
							
							e.srcElement.innerHTML = "Deploy Contract";
							startApp(window.web3);
						}
						// Non-dapp browsers...
						else {
							e.srcElement.innerHTML = "Deploy Contract";
							alert('Non-Ethereum browser detected. You should consider trying MetaMask!');
						}
					});

					function startApp(web3) {
						const eth = new Eth(web3.currentProvider);
						const contract = new EthContract(eth);
							
						eth.accounts().then((accounts) => {		
							const contractFactory = eth.contract(contractABI, contractBytecode, {
								from: accounts[0],
								gas: 470000,
							});

							// create a new contract
							contractFactory.new((error, result) => {
								// result null '0x928sdfk...' (i.e. the transaction hash)
							});
						});
					}
					
				} catch (e) {
					alert("Caught! " + e.message);
				}
				</script>
				
			</div>
			<!-- /#page-content-wrapper -->

		</div>
		<!-- /#wrapper -->
	</body>
	
	<script src="../media/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
	<script src="../media/vendor/enlighter/js/enlighterjs.min.js"></script>
	<!-- Menu Toggle Script -->
	<script type="text/javascript">
	$("#menu-toggle").click(function(e) {
		e.preventDefault();
		$("#wrapper").toggleClass("toggled");
	});
  
	// - highlight all pre + code tags (CSS3 selectors)
	// - use javascript as default language
	// - use theme "enlighter" as default theme
	// - replace tabs with 2 spaces
	EnlighterJS.init('pre', 'code', {
		language : 'php',
		theme: 'enlighter',
		indent : 4
	});

	$(document).ready(function(){		
		$('[data-toggle="tooltip"]').tooltip();
	});
	</script>
	<script type="text/javascript" src="../media/vendor/iframeresizer/js/iframeResizer.contentWindow.min.js"></script> 
</html>			
pragma solidity ^0.5.0;


import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0/contracts/math/SafeMath.sol";

contract MultiSendEth  {
    
    using SafeMath for uint256;
   
    address public owner;
    
    modifier onlyOwner(){
        require(msg.sender == owner);
        _;
    }
    
    constructor() public{
        owner = msg.sender;
    }
   
    //accept eth deposit
    function() external payable  {
        require(msg.data.length == 0); //to prevent invalid calls.
    }
    
    //getowner
    function getOwner() public view returns (address) {
        return owner;
    }
    
    //get eth balance
    function getEthBalance() public view returns (uint256) {
        return address(this).balance;
    }
    
    //withdraw whole balance
    function withdraw() public onlyOwner{
        msg.sender.transfer(address(this).balance);
    }
    
    //batch send fixed eth amount from sender
    function multiSendFixedEth(address payable[] memory recipients, uint256 amount) public payable {
        
        require(recipients.length > 0);
        require(amount > 0);
        require(recipients.length * amount == msg.value);
        
        uint256 length = recipients.length;
        
        for(uint256 i=0;i<length;i++) {
            recipients[i].transfer(amount);
        }
    }   
    
    //batch send different eth amount from sender
    function multiSendDiffEth(address payable[] memory recipients, uint256[] memory amounts) public payable {
        require(recipients.length > 0);
        require(recipients.length == amounts.length);
        
        uint256 length = recipients.length;
        uint256 currentSum = 0;
        
        for (uint256 i = 0; i < length; i++) {
            uint256 amount = amounts[i];
            require(amount > 0);
            currentSum = currentSum.add(amount);
            require(currentSum <= msg.value);
           
            recipients[i].transfer(amount);
        }
        
    }
    
	
    //batch send fixed eth amount from contract
    function multiSendFixedEthFromContract(address payable[] memory recipients, uint256 amount) public onlyOwner {
        
        require(recipients.length > 0);
        require(amount > 0);
        require(recipients.length * amount <= address(this).balance);
        
        uint256 length = recipients.length;
		
        for(uint256 i=0;i<length;i++) {
            recipients[i].transfer(amount);
        }
    }    
    
    //batch send different eth amount from contract
    function multiSendDiffEthFromContract(address payable[] memory recipients, uint256[] memory amounts) public onlyOwner {
        
        require(recipients.length > 0);
        require(recipients.length == amounts.length);
        
        uint256 length = recipients.length;
        uint256 currentSum = 0;
        uint256 currentEthBalance = address(this).balance;
        
        for (uint256 i = 0; i < length; i++) {
            uint256 amount = amounts[i];
            require(amount > 0);
            currentSum = currentSum.add(amount);
            require(currentSum <= currentEthBalance);
           
            recipients[i].transfer(amount);
        }
    }    
}








Tutorials
About Us
Contents have been open source in GITHUB. Please give me a ⭐ if you found this helpful :)
Community
Problem? Raise me a new issue.
Support Us
Buy me a coffee. so i can spend more nights for this :)

BTCSCHOOLS would like to present you with more pratical but little theory throughout our tutorials. Pages' content are constantly keep reviewed to avoid mistakes, but we cannot warrant correctness of all contents. While using this site, you agree to accept our terms of use, cookie & privacy policy. Copyright 2019 by BTCSCHOOLS. All Rights Reserved.