Heritable.sol 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. pragma solidity ^0.4.23;
  2. import "./Ownable.sol";
  3. /**
  4. * @title Heritable
  5. * @dev The Heritable contract provides ownership transfer capabilities, in the
  6. * case that the current owner stops "heartbeating". Only the heir can pronounce the
  7. * owner's death.
  8. */
  9. contract Heritable is Ownable {
  10. address private heir_;
  11. // Time window the owner has to notify they are alive.
  12. uint256 private heartbeatTimeout_;
  13. // Timestamp of the owner's death, as pronounced by the heir.
  14. uint256 private timeOfDeath_;
  15. event HeirChanged(address indexed owner, address indexed newHeir);
  16. event OwnerHeartbeated(address indexed owner);
  17. event OwnerProclaimedDead(address indexed owner, address indexed heir, uint256 timeOfDeath);
  18. event HeirOwnershipClaimed(address indexed previousOwner, address indexed newOwner);
  19. /**
  20. * @dev Throw an exception if called by any account other than the heir's.
  21. */
  22. modifier onlyHeir() {
  23. require(msg.sender == heir_);
  24. _;
  25. }
  26. /**
  27. * @notice Create a new Heritable Contract with heir address 0x0.
  28. * @param _heartbeatTimeout time available for the owner to notify they are alive,
  29. * before the heir can take ownership.
  30. */
  31. constructor(uint256 _heartbeatTimeout) public {
  32. setHeartbeatTimeout(_heartbeatTimeout);
  33. }
  34. function setHeir(address newHeir) public onlyOwner {
  35. require(newHeir != owner);
  36. heartbeat();
  37. emit HeirChanged(owner, newHeir);
  38. heir_ = newHeir;
  39. }
  40. /**
  41. * @dev Use these getter functions to access the internal variables in
  42. * an inherited contract.
  43. */
  44. function heir() public view returns(address) {
  45. return heir_;
  46. }
  47. function heartbeatTimeout() public view returns(uint256) {
  48. return heartbeatTimeout_;
  49. }
  50. function timeOfDeath() public view returns(uint256) {
  51. return timeOfDeath_;
  52. }
  53. /**
  54. * @dev set heir = 0x0
  55. */
  56. function removeHeir() public onlyOwner {
  57. heartbeat();
  58. heir_ = 0;
  59. }
  60. /**
  61. * @dev Heir can pronounce the owners death. To claim the ownership, they will
  62. * have to wait for `heartbeatTimeout` seconds.
  63. */
  64. function proclaimDeath() public onlyHeir {
  65. require(ownerLives());
  66. emit OwnerProclaimedDead(owner, heir_, timeOfDeath_);
  67. // solium-disable-next-line security/no-block-members
  68. timeOfDeath_ = block.timestamp;
  69. }
  70. /**
  71. * @dev Owner can send a heartbeat if they were mistakenly pronounced dead.
  72. */
  73. function heartbeat() public onlyOwner {
  74. emit OwnerHeartbeated(owner);
  75. timeOfDeath_ = 0;
  76. }
  77. /**
  78. * @dev Allows heir to transfer ownership only if heartbeat has timed out.
  79. */
  80. function claimHeirOwnership() public onlyHeir {
  81. require(!ownerLives());
  82. // solium-disable-next-line security/no-block-members
  83. require(block.timestamp >= timeOfDeath_ + heartbeatTimeout_);
  84. emit OwnershipTransferred(owner, heir_);
  85. emit HeirOwnershipClaimed(owner, heir_);
  86. owner = heir_;
  87. timeOfDeath_ = 0;
  88. }
  89. function setHeartbeatTimeout(uint256 newHeartbeatTimeout) internal onlyOwner {
  90. require(ownerLives());
  91. heartbeatTimeout_ = newHeartbeatTimeout;
  92. }
  93. function ownerLives() internal view returns (bool) {
  94. return timeOfDeath_ == 0;
  95. }
  96. }