From 96bf5a5fafd71f2760a9c379ff9c7515e49a994c Mon Sep 17 00:00:00 2001 From: Ariel Barmat Date: Tue, 29 Aug 2017 03:40:41 -0300 Subject: [PATCH] Add a SplitPullPayment contract that combines distribution of funds and delayed withdrawal from each party --- contracts/payment/SplitPullPayment.sol | 28 +++++++++++++++++ test/SplitPullPayment.js | 42 ++++++++++++++++++++++++++ test/helpers/SplitPullPaymentMock.sol | 9 ++++++ 3 files changed, 79 insertions(+) create mode 100644 contracts/payment/SplitPullPayment.sol create mode 100644 test/SplitPullPayment.js create mode 100644 test/helpers/SplitPullPaymentMock.sol diff --git a/contracts/payment/SplitPullPayment.sol b/contracts/payment/SplitPullPayment.sol new file mode 100644 index 00000000000..0f0ef9ba61f --- /dev/null +++ b/contracts/payment/SplitPullPayment.sol @@ -0,0 +1,28 @@ +pragma solidity ^0.4.15; + +import './PullPayment.sol'; +import './SplitPayment.sol'; + +/** + * @title SplitPullPayment + * @dev Contract supporting the distribution of funds combined with withdrawals through PullPayment. + */ +contract SplitPullPayment is SplitPayment, PullPayment { + /** + * @dev Return the total amount of funds available for distribution. + * @dev Override from SplitPayment to take into account credited funds for pull payments. + */ + function toDistribute() internal returns (uint256) { + return this.balance.sub(totalPayments); + } + + /** + * @dev Perform the payment to a payee. + * @dev Override from SplitPayment to do an asyncSend for later withdrawal. + * @param _payee The address of the payee to be paid. + * @param _amount The amount for the payment. + */ + function pay(address _payee, uint256 _amount) internal { + asyncSend(_payee, _amount); + } +} diff --git a/test/SplitPullPayment.js b/test/SplitPullPayment.js new file mode 100644 index 00000000000..77560533902 --- /dev/null +++ b/test/SplitPullPayment.js @@ -0,0 +1,42 @@ +const BigNumber = web3.BigNumber + +const should = require('chai') + .use(require('chai-as-promised')) + .use(require('chai-bignumber')(BigNumber)) + .should() + +const EVMThrow = require('./helpers/EVMThrow.js') +const SplitPullPaymentMock = artifacts.require('./helpers/SplitPullPaymentMock.sol') + +contract('SplitPullPayment', function ([owner, payee1, payee2, payee3, nonpayee1, payer1]) { + const amount = web3.toWei(1.0, 'ether') + + beforeEach(async function () { + this.payees = [payee1, payee2, payee3] + this.shares = [20, 10, 70] + + this.contract = await SplitPullPaymentMock.new() + await this.contract.addPayeeMany(this.payees, this.shares) + }) + + it('should distribute funds to payees', async function () { + await web3.eth.sendTransaction({from: payer1, to: this.contract.address, value: amount}) + + await this.contract.distributeFunds({from: payee1}) + + const amount1 = await this.contract.payments.call(payee1) + amount1.should.be.bignumber.equal(web3.toWei(0.20, 'ether')) + + const amount2 = await this.contract.payments.call(payee2) + amount2.should.be.bignumber.equal(web3.toWei(0.10, 'ether')) + + const amount3 = await this.contract.payments.call(payee3) + amount3.should.be.bignumber.equal(web3.toWei(0.70, 'ether')) + + const balance = web3.eth.getBalance(this.contract.address) + balance.should.be.bignumber.equal(amount) + + const totalPayments = await this.contract.totalPayments.call() + balance.should.be.bignumber.equal(amount) + }) +}) diff --git a/test/helpers/SplitPullPaymentMock.sol b/test/helpers/SplitPullPaymentMock.sol new file mode 100644 index 00000000000..559c80f6c2c --- /dev/null +++ b/test/helpers/SplitPullPaymentMock.sol @@ -0,0 +1,9 @@ +pragma solidity ^0.4.15; + +import '../../contracts/payment/SplitPullPayment.sol'; + +// mock class using SplitPullPaymentMock +contract SplitPullPaymentMock is SplitPullPayment { + function SplitPullPaymentMock() SplitPayment(0) payable { } + function () payable {} +}