mirror of openzeppelin-contracts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openzeppelin-contracts/contracts/payment/SplitPayment.sol

149 lines
4.1 KiB

pragma solidity ^0.4.15;
import '../ReentrancyGuard.sol';
import '../math/SafeMath.sol';
/**
* @title SplitPayment
* @dev Base contract supporting the distribution of funds send to this contract to multiple payees.
*/
contract SplitPayment is ReentrancyGuard {
using SafeMath for uint256;
struct Payee {
address addr;
uint256 shares;
}
uint256 public totalShares = 0;
uint256 public maxPayees = 0;
mapping(address => uint256) payeeIndex;
Payee[] payees;
/**
* @dev Constructor
* @param _maxPayees Total number of payees allowed. Zero for no limit.
*/
function SplitPayment(uint256 _maxPayees) {
maxPayees = _maxPayees;
}
/**
* @dev Modifier that throws if you want to distribute funds and you are not a payee.
*/
modifier canDistribute() {
require(isPayee(msg.sender));
_;
}
/**
* @dev Modifier that throws if not allowed to update payees.
* Override from child contract with your own requirements for access control.
*/
modifier canUpdate() {
_;
}
/**
* @dev Add a new payee to the contract.
* @param _payee The address of the payee to add.
* @param _shares The number of shares owned by the payee.
*/
function addPayee(address _payee, uint256 _shares) public canUpdate {
require(_payee != address(0));
require(_shares > 0);
require(!isPayee(_payee));
require(maxPayees == 0 || payees.length.add(1) <= maxPayees);
payees.push(Payee(_payee, _shares));
payeeIndex[_payee] = payees.length;
totalShares = totalShares.add(_shares);
}
/**
* @dev Add multiple payees to the contract.
* @param _payees An array of addresses of payees to add.
* @param _shares An array of the shares corresponding to each payee in the _payees array.
*/
function addPayeeMany(address[] _payees, uint256[] _shares) public canUpdate {
require(_payees.length == _shares.length);
require(maxPayees == 0 || payees.length.add(_payees.length) <= maxPayees);
for (uint256 i = 0; i < _payees.length; i++) {
addPayee(_payees[i], _shares[i]);
}
}
/**
* @dev Return true if the payee is in the contract.
* @param _payee The address of the payee to check.
*/
function isPayee(address _payee) public constant returns (bool) {
return payeeIndex[_payee] > 0;
}
/**
* @dev Return the number of payees in the contract.
*/
function getPayeeCount() public constant returns (uint256) {
return payees.length;
}
/**
* @dev Return the address of the payee and its shares.
* Throws if the payee is not in the contract.
* @param _payee The address of the payee to get.
*/
function getPayee(address _payee) public constant returns (address, uint256) {
require(isPayee(_payee));
return getPayeeAtIndex(payeeIndex[_payee] - 1);
}
/**
* @dev Return the address of the payee and its shares by index.
* Allows iterating through the payee list from a client by knowing the payee count.
* @param _idx The index of the payee in the internal list.
*/
function getPayeeAtIndex(uint256 _idx) public constant returns (address, uint256) {
require(_idx < payees.length);
return (payees[_idx].addr, payees[_idx].shares);
}
/**
* @dev Perform the payment to a payee.
* This can be overriden to provide different transfer mechanisms.
* @param _payee The address of the payee to be paid.
* @param _amount The amount for the payment.
*/
function pay(address _payee, uint256 _amount) internal {
_payee.transfer(_amount);
}
/**
* @dev Return the total amount of funds available for distribution.
*/
function toDistribute() internal returns (uint256) {
return this.balance;
}
/**
* @dev Send payments to the registered payees according to their shares and the total
* amount of funds to distribute.
*/
function distributeFunds() public canDistribute nonReentrant {
uint256 amountDistribute = toDistribute();
assert(amountDistribute > 0);
Payee memory payee;
for (uint256 i = 0; i < payees.length; i++) {
payee = payees[i];
uint256 amount = amountDistribute.mul(payee.shares).div(totalShares);
pay(payee.addr, amount);
}
}
}