SplitPayment.sol 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. pragma solidity ^0.4.15;
  2. import '../ReentrancyGuard.sol';
  3. import '../math/SafeMath.sol';
  4. /**
  5. * @title SplitPayment
  6. * @dev Base contract supporting the distribution of funds send to this contract to multiple payees.
  7. */
  8. contract SplitPayment is ReentrancyGuard {
  9. using SafeMath for uint256;
  10. struct Payee {
  11. address addr;
  12. uint256 shares;
  13. }
  14. uint256 public totalShares = 0;
  15. uint256 public maxPayees = 0;
  16. mapping(address => uint256) payeeIndex;
  17. Payee[] payees;
  18. /**
  19. * @dev Constructor
  20. * @param _maxPayees Total number of payees allowed. Zero for no limit.
  21. */
  22. function SplitPayment(uint256 _maxPayees) {
  23. maxPayees = _maxPayees;
  24. }
  25. /**
  26. * @dev Modifier that throws if you want to distribute funds and you are not a payee.
  27. */
  28. modifier canDistribute() {
  29. require(isPayee(msg.sender));
  30. _;
  31. }
  32. /**
  33. * @dev Modifier that throws if not allowed to update payees.
  34. * Override from child contract with your own requirements for access control.
  35. */
  36. modifier canUpdate() {
  37. _;
  38. }
  39. /**
  40. * @dev Add a new payee to the contract.
  41. * @param _payee The address of the payee to add.
  42. * @param _shares The number of shares owned by the payee.
  43. */
  44. function addPayee(address _payee, uint256 _shares) public canUpdate {
  45. require(_payee != address(0));
  46. require(_shares > 0);
  47. require(!isPayee(_payee));
  48. require(maxPayees == 0 || payees.length.add(1) <= maxPayees);
  49. payees.push(Payee(_payee, _shares));
  50. payeeIndex[_payee] = payees.length;
  51. totalShares = totalShares.add(_shares);
  52. }
  53. /**
  54. * @dev Add multiple payees to the contract.
  55. * @param _payees An array of addresses of payees to add.
  56. * @param _shares An array of the shares corresponding to each payee in the _payees array.
  57. */
  58. function addPayeeMany(address[] _payees, uint256[] _shares) public canUpdate {
  59. require(_payees.length == _shares.length);
  60. require(maxPayees == 0 || payees.length.add(_payees.length) <= maxPayees);
  61. for (uint256 i = 0; i < _payees.length; i++) {
  62. addPayee(_payees[i], _shares[i]);
  63. }
  64. }
  65. /**
  66. * @dev Return true if the payee is in the contract.
  67. * @param _payee The address of the payee to check.
  68. */
  69. function isPayee(address _payee) public constant returns (bool) {
  70. return payeeIndex[_payee] > 0;
  71. }
  72. /**
  73. * @dev Return the number of payees in the contract.
  74. */
  75. function getPayeeCount() public constant returns (uint256) {
  76. return payees.length;
  77. }
  78. /**
  79. * @dev Return the address of the payee and its shares.
  80. * Throws if the payee is not in the contract.
  81. * @param _payee The address of the payee to get.
  82. */
  83. function getPayee(address _payee) public constant returns (address, uint256) {
  84. require(isPayee(_payee));
  85. return getPayeeAtIndex(payeeIndex[_payee] - 1);
  86. }
  87. /**
  88. * @dev Return the address of the payee and its shares by index.
  89. * Allows iterating through the payee list from a client by knowing the payee count.
  90. * @param _idx The index of the payee in the internal list.
  91. */
  92. function getPayeeAtIndex(uint256 _idx) public constant returns (address, uint256) {
  93. require(_idx < payees.length);
  94. return (payees[_idx].addr, payees[_idx].shares);
  95. }
  96. /**
  97. * @dev Perform the payment to a payee.
  98. * This can be overriden to provide different transfer mechanisms.
  99. * @param _payee The address of the payee to be paid.
  100. * @param _amount The amount for the payment.
  101. */
  102. function pay(address _payee, uint256 _amount) internal {
  103. _payee.transfer(_amount);
  104. }
  105. /**
  106. * @dev Return the total amount of funds available for distribution.
  107. */
  108. function toDistribute() internal returns (uint256) {
  109. return this.balance;
  110. }
  111. /**
  112. * @dev Send payments to the registered payees according to their shares and the total
  113. * amount of funds to distribute.
  114. */
  115. function distributeFunds() public canDistribute nonReentrant {
  116. uint256 amountDistribute = toDistribute();
  117. assert(amountDistribute > 0);
  118. Payee memory payee;
  119. for (uint256 i = 0; i < payees.length; i++) {
  120. payee = payees[i];
  121. uint256 amount = amountDistribute.mul(payee.shares).div(totalShares);
  122. pay(payee.addr, amount);
  123. }
  124. }
  125. }