Skip to content
Prev Previous commit
Next Next commit
RefundEscrow is now Secondary.
  • Loading branch information
nventuro committed Sep 6, 2018
commit 14e9db0b5c5324592c508be64df2d1666a464420
14 changes: 7 additions & 7 deletions contracts/payment/RefundEscrow.sol
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
pragma solidity ^0.4.23;

import "./ConditionalEscrow.sol";
import "../ownership/Ownable.sol";
import "../ownership/Secondary.sol";


/**
* @title RefundEscrow
* @dev Escrow that holds funds for a beneficiary, deposited from multiple parties.
* The contract owner may close the deposit period, and allow for either withdrawal
* The primary account may close the deposit period, and allow for either withdrawal
* by the beneficiary, or refunds to the depositors.
*/
contract RefundEscrow is Ownable, ConditionalEscrow {
contract RefundEscrow is Secondary, ConditionalEscrow {
enum State { Active, Refunding, Closed }

event Closed();
Expand All @@ -32,14 +32,14 @@ contract RefundEscrow is Ownable, ConditionalEscrow {
/**
* @return the current state of the escrow.
*/
function state() public view returns(State) {
function state() public view returns (State) {
return state_;
}

/**
* @return the beneficiary of the escrow.
*/
function beneficiary() public view returns(address) {
function beneficiary() public view returns (address) {
return beneficiary_;
}

Expand All @@ -56,7 +56,7 @@ contract RefundEscrow is Ownable, ConditionalEscrow {
* @dev Allows for the beneficiary to withdraw their funds, rejecting
* further deposits.
*/
function close() public onlyOwner {
function close() public onlyPrimary {
require(state_ == State.Active);
state_ = State.Closed;
emit Closed();
Expand All @@ -65,7 +65,7 @@ contract RefundEscrow is Ownable, ConditionalEscrow {
/**
* @dev Allows for refunds to take place, rejecting further deposits.
*/
function enableRefunds() public onlyOwner {
function enableRefunds() public onlyPrimary {
require(state_ == State.Active);
state_ = State.Refunding;
emit RefundsEnabled();
Expand Down
42 changes: 21 additions & 21 deletions test/payment/RefundEscrow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ require('chai')

const RefundEscrow = artifacts.require('RefundEscrow');

contract('RefundEscrow', function ([_, owner, beneficiary, refundee1, refundee2]) {
contract('RefundEscrow', function ([_, primary, beneficiary, refundee1, refundee2]) {
const amount = web3.toWei(54.0, 'ether');
const refundees = [refundee1, refundee2];
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';

it('requires a non-null beneficiary', async function () {
await expectThrow(
RefundEscrow.new(ZERO_ADDRESS, { from: owner })
RefundEscrow.new(ZERO_ADDRESS, { from: primary })
);
});

context('once deployed', function () {
beforeEach(async function () {
this.escrow = await RefundEscrow.new(beneficiary, { from: owner });
this.escrow = await RefundEscrow.new(beneficiary, { from: primary });
});

context('active state', function () {
Expand All @@ -34,39 +34,39 @@ contract('RefundEscrow', function ([_, owner, beneficiary, refundee1, refundee2]
});

it('accepts deposits', async function () {
await this.escrow.deposit(refundee1, { from: owner, value: amount });
await this.escrow.deposit(refundee1, { from: primary, value: amount });

(await this.escrow.depositsOf(refundee1)).should.be.bignumber.equal(amount);
});

it('does not refund refundees', async function () {
await this.escrow.deposit(refundee1, { from: owner, value: amount });
await this.escrow.deposit(refundee1, { from: primary, value: amount });
await expectThrow(this.escrow.withdraw(refundee1), EVMRevert);
});

it('does not allow beneficiary withdrawal', async function () {
await this.escrow.deposit(refundee1, { from: owner, value: amount });
await this.escrow.deposit(refundee1, { from: primary, value: amount });
await expectThrow(this.escrow.beneficiaryWithdraw(), EVMRevert);
});
});

it('only owner can enter closed state', async function () {
it('only the primary account can enter closed state', async function () {
await expectThrow(this.escrow.close({ from: beneficiary }), EVMRevert);

const receipt = await this.escrow.close({ from: owner });
const receipt = await this.escrow.close({ from: primary });

expectEvent.inLogs(receipt.logs, 'Closed');
});

context('closed state', function () {
beforeEach(async function () {
await Promise.all(refundees.map(refundee => this.escrow.deposit(refundee, { from: owner, value: amount })));
await Promise.all(refundees.map(refundee => this.escrow.deposit(refundee, { from: primary, value: amount })));

await this.escrow.close({ from: owner });
await this.escrow.close({ from: primary });
});

it('rejects deposits', async function () {
await expectThrow(this.escrow.deposit(refundee1, { from: owner, value: amount }), EVMRevert);
await expectThrow(this.escrow.deposit(refundee1, { from: primary, value: amount }), EVMRevert);
});

it('does not refund refundees', async function () {
Expand All @@ -82,37 +82,37 @@ contract('RefundEscrow', function ([_, owner, beneficiary, refundee1, refundee2]
});

it('prevents entering the refund state', async function () {
await expectThrow(this.escrow.enableRefunds({ from: owner }), EVMRevert);
await expectThrow(this.escrow.enableRefunds({ from: primary }), EVMRevert);
});

it('prevents re-entering the closed state', async function () {
await expectThrow(this.escrow.close({ from: owner }), EVMRevert);
await expectThrow(this.escrow.close({ from: primary }), EVMRevert);
});
});

it('only owner can enter refund state', async function () {
it('only the primary account can enter refund state', async function () {
await expectThrow(this.escrow.enableRefunds({ from: beneficiary }), EVMRevert);

const receipt = await this.escrow.enableRefunds({ from: owner });
const receipt = await this.escrow.enableRefunds({ from: primary });

expectEvent.inLogs(receipt.logs, 'RefundsEnabled');
});

context('refund state', function () {
beforeEach(async function () {
await Promise.all(refundees.map(refundee => this.escrow.deposit(refundee, { from: owner, value: amount })));
await Promise.all(refundees.map(refundee => this.escrow.deposit(refundee, { from: primary, value: amount })));

await this.escrow.enableRefunds({ from: owner });
await this.escrow.enableRefunds({ from: primary });
});

it('rejects deposits', async function () {
await expectThrow(this.escrow.deposit(refundee1, { from: owner, value: amount }), EVMRevert);
await expectThrow(this.escrow.deposit(refundee1, { from: primary, value: amount }), EVMRevert);
});

it('refunds refundees', async function () {
for (const refundee of [refundee1, refundee2]) {
const refundeeInitialBalance = await ethGetBalance(refundee);
await this.escrow.withdraw(refundee, { from: owner });
await this.escrow.withdraw(refundee, { from: primary });
const refundeeFinalBalance = await ethGetBalance(refundee);

refundeeFinalBalance.sub(refundeeInitialBalance).should.be.bignumber.equal(amount);
Expand All @@ -124,11 +124,11 @@ contract('RefundEscrow', function ([_, owner, beneficiary, refundee1, refundee2]
});

it('prevents entering the closed state', async function () {
await expectThrow(this.escrow.close({ from: owner }), EVMRevert);
await expectThrow(this.escrow.close({ from: primary }), EVMRevert);
});

it('prevents re-entering the refund state', async function () {
await expectThrow(this.escrow.enableRefunds({ from: owner }), EVMRevert);
await expectThrow(this.escrow.enableRefunds({ from: primary }), EVMRevert);
});
});
});
Expand Down