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.
149 lines
4.1 KiB
149 lines
4.1 KiB
8 years ago
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|