Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
renamed Inheritable --> Heritable
  • Loading branch information
azavalla committed Nov 30, 2017
commit 6853b3d37670983f7cc6eade4520975bfcefc541
11 changes: 6 additions & 5 deletions contracts/examples/SimpleSavingsWallet.sol
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
pragma solidity ^0.4.11;

import "../ownership/Inheritable.sol";
import "../ownership/Heritable.sol";


/**
* @title SimpleSavingsWallet
* @dev Simplest form of savings wallet that can be inherited if owner dies.
* @dev Simplest form of savings wallet whose ownership can be claimed by a heir
* if owner dies.
* In this example, we take a very simple savings wallet providing two operations
* (to send and receive funds) and extend its capabilities by making it Inheritable.
* (to send and receive funds) and extend its capabilities by making it Heritable.
* The account that creates the contract is set as owner, who has the authority to
* choose an heir account. Heir account can reclaim the contract ownership in the
* case that the owner dies.
*/
contract SimpleSavingsWallet is Inheritable {
contract SimpleSavingsWallet is Heritable {

event Sent(address payee, uint amount, uint balance);
event Received(address payer, uint amount, uint balance);


function SimpleSavingsWallet(uint _heartbeatTimeout) Inheritable(_heartbeatTimeout) public {}
function SimpleSavingsWallet(uint _heartbeatTimeout) Heritable(_heartbeatTimeout) public {}

/**
* @dev wallet can receive funds.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import './Ownable.sol';


/**
* @title Inheritable
* @dev The Inheritable contract provides ownership transfer capabilities, in the
* @title Heritable
* @dev The Heritable contract provides ownership transfer capabilities, in the
* case that the current owner stops "heartbeating". Only the heir can pronounce the
* owner's death.
*/
contract Inheritable is Ownable {
contract Heritable is Ownable {
address public heir;

// Time window the owner has to notify they are alive.
Expand All @@ -35,11 +35,11 @@ contract Inheritable is Ownable {


/**
* @notice Create a new Inheritable Contract with heir address 0x0.
* @notice Create a new Heritable Contract with heir address 0x0.
* @param _heartbeatTimeout time available for the owner to notify they are alive,
* before the heir can take ownership.
*/
function Inheritable(uint _heartbeatTimeout) public {
function Heritable(uint _heartbeatTimeout) public {
setHeartbeatTimeout(_heartbeatTimeout);
}

Expand All @@ -59,7 +59,7 @@ contract Inheritable is Ownable {
}

/**
* @dev Heir can pronounce the owners death. To inherit the ownership, they will
* @dev Heir can pronounce the owners death. To claim the ownership, they will
* have to wait for `heartbeatTimeout` seconds.
*/
function proclaimDeath() public onlyHeir {
Expand All @@ -79,7 +79,7 @@ contract Inheritable is Ownable {
/**
* @dev Allows heir to transfer ownership only if heartbeat has timed out.
*/
function inherit() public onlyHeir {
function claimHeirOwnership() public onlyHeir {
require(!ownerLives());
require(now >= timeOfDeath + heartbeatTimeout);
OwnershipTransferred(owner, heir);
Expand Down
64 changes: 32 additions & 32 deletions test/Inheritable.js → test/Heritable.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ import expectThrow from './helpers/expectThrow';

const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'

const Inheritable = artifacts.require('../contracts/ownership/Inheritable.sol')
const Heritable = artifacts.require('../contracts/ownership/Heritable.sol')

contract('Inheritable', function(accounts) {
let inheritable
contract('Heritable', function(accounts) {
let heritable
let owner

beforeEach(async function() {
inheritable = await Inheritable.new(4141)
owner = await inheritable.owner()
heritable = await Heritable.new(4141)
owner = await heritable.owner()
})

it('should start off with an owner, but without heir', async function() {
const heir = await inheritable.heir()
const heir = await heritable.heir()

assert.equal(typeof(owner), 'string')
assert.equal(typeof(heir), 'string')
Expand All @@ -35,72 +35,72 @@ contract('Inheritable', function(accounts) {
const someRandomAddress = accounts[2]
assert.isTrue(owner !== someRandomAddress)

await inheritable.setHeir(newHeir, {from: owner})
await expectThrow(inheritable.setHeir(newHeir, {from: someRandomAddress}))
await heritable.setHeir(newHeir, {from: owner})
await expectThrow(heritable.setHeir(newHeir, {from: someRandomAddress}))
})

it('owner can remove heir', async function() {
const newHeir = accounts[1]
await inheritable.setHeir(newHeir, {from: owner})
let heir = await inheritable.heir()
await heritable.setHeir(newHeir, {from: owner})
let heir = await heritable.heir()

assert.notStrictEqual(heir, NULL_ADDRESS)
await inheritable.removeHeir()
heir = await inheritable.heir()
await heritable.removeHeir()
heir = await heritable.heir()
assert.isTrue(heir === NULL_ADDRESS)
})

it('heir can inherit only if owner is dead and timeout was reached', async function() {
it('heir can claim ownership only if owner is dead and timeout was reached', async function() {
const heir = accounts[1]
await inheritable.setHeir(heir, {from: owner})
await expectThrow(inheritable.inherit({from: heir}))
await heritable.setHeir(heir, {from: owner})
await expectThrow(heritable.claimHeirOwnership({from: heir}))

await inheritable.proclaimDeath({from: heir})
await heritable.proclaimDeath({from: heir})
await increaseTime(1)
await expectThrow(inheritable.inherit({from: heir}))
await expectThrow(heritable.claimHeirOwnership({from: heir}))

await increaseTime(4141)
await inheritable.inherit({from: heir})
assert.isTrue(await inheritable.heir() === heir)
await heritable.claimHeirOwnership({from: heir})
assert.isTrue(await heritable.heir() === heir)
})

it('heir can\'t inherit if owner heartbeats', async function() {
it('heir can\'t claim ownership if owner heartbeats', async function() {
const heir = accounts[1]
await inheritable.setHeir(heir, {from: owner})
await heritable.setHeir(heir, {from: owner})

await inheritable.proclaimDeath({from: heir})
await inheritable.heartbeat({from: owner})
await expectThrow(inheritable.inherit({from: heir}))
await heritable.proclaimDeath({from: heir})
await heritable.heartbeat({from: owner})
await expectThrow(heritable.claimHeirOwnership({from: heir}))

await inheritable.proclaimDeath({from: heir})
await heritable.proclaimDeath({from: heir})
await increaseTime(4141)
await inheritable.heartbeat({from: owner})
await expectThrow(inheritable.inherit({from: heir}))
await heritable.heartbeat({from: owner})
await expectThrow(heritable.claimHeirOwnership({from: heir}))
})

it('should log events appropriately', async function() {
const heir = accounts[1]

const setHeirLogs = (await inheritable.setHeir(heir, {from: owner})).logs
const setHeirLogs = (await heritable.setHeir(heir, {from: owner})).logs
const setHeirEvent = setHeirLogs.find(e => e.event === 'HeirChanged')

assert.isTrue(setHeirEvent.args.owner === owner)
assert.isTrue(setHeirEvent.args.newHeir === heir)

const heartbeatLogs = (await inheritable.heartbeat({from: owner})).logs
const heartbeatLogs = (await heritable.heartbeat({from: owner})).logs
const heartbeatEvent = heartbeatLogs.find(e => e.event === 'OwnerHeartbeated')

assert.isTrue(heartbeatEvent.args.owner === owner)

const proclaimDeathLogs = (await inheritable.proclaimDeath({from: heir})).logs
const proclaimDeathLogs = (await heritable.proclaimDeath({from: heir})).logs
const ownerDeadEvent = proclaimDeathLogs.find(e => e.event === 'OwnerProclaimedDead')

assert.isTrue(ownerDeadEvent.args.owner === owner)
assert.isTrue(ownerDeadEvent.args.heir === heir)

await increaseTime(4141)
const inheritLogs = (await inheritable.inherit({from: heir})).logs
const ownershipTransferredEvent = inheritLogs.find(e => e.event === 'OwnershipTransferred')
const claimHeirOwnershipLogs = (await heritable.claimHeirOwnership({from: heir})).logs
const ownershipTransferredEvent = claimHeirOwnershipLogs.find(e => e.event === 'OwnershipTransferred')

assert.isTrue(ownershipTransferredEvent.args.previousOwner === owner)
assert.isTrue(ownershipTransferredEvent.args.newOwner === heir)
Expand Down