pragma solidity ^0.5.0; // NOTE: // The architecture of all proxies and the ProxyFactory-contract // has been modelled upon this blogpost by Alan Lu: // https://blog.gnosis.pm/solidity-delegateproxy-contracts-e09957d0f201 import "./Assessment.sol"; import "./Concept.sol"; import "./AssessmentProxy.sol"; import "./ConceptProxy.sol"; /** @dev Factory for assessment- and concept-proxy contracts. */ contract ProxyFactory { // Proxied address for concepts, used by Proxy.sol-constructor to generate // storage layout address public masterConceptCopy; // Proxied address for assessments address public masterAssessmentCopy; address public owner; // Period of time before which proposed changes take effect, so that // disagreeing members to fork the network uint public timelimit = 7 days; // Proposed changes address public proposedMasterAssessment; address public proposedOwner; uint public proposedTimelimit; // Date the proposal has been submitted uint public proposalDate; event ProposedChange ( address proposedMasterAssessment, address proposedOwner, uint proposedTimelimit ); event ChangeImplemented ( address proposedMasterAssessment, address proposedOwner, uint proposedTimelimit ); /** @dev Save address of masterCopies for concept and assessment proxies */ constructor(address _masterConcept, address _masterAssessment) public { owner = msg.sender; masterConceptCopy = _masterConcept; masterAssessmentCopy = _masterAssessment; } function proposeChange( address _proposedMasterAssessment, address _proposedOwner, uint _proposedTimelimit ) public { require(msg.sender == owner, "Owner access only"); require(isContract(_proposedMasterAssessment), "New assessment-address must be a contract"); proposedMasterAssessment = _proposedMasterAssessment; proposedOwner = _proposedOwner; proposedTimelimit = _proposedTimelimit; proposalDate = now; emit ProposedChange(_proposedMasterAssessment, _proposedOwner, _proposedTimelimit); } function implementChange() public { require(msg.sender == owner, "Owner access only"); require(now - proposalDate > timelimit, "TimeLimit must pass before change can be implemented"); masterAssessmentCopy = proposedMasterAssessment; owner = proposedOwner; timelimit = proposedTimelimit; // REFACTOR could cleanup the proposed* storage variables emit ChangeImplemented(proposedMasterAssessment, proposedOwner, proposedTimelimit); } /** @notice Called by concept-contracts to create an assessment in them */ function createAssessment(address _assessee, uint _cost, uint _size, uint _waitTime, uint _timeLimit) public returns (address) { return address(new AssessmentProxy( masterAssessmentCopy, msg.sender, _assessee, _cost, _size, _waitTime, _timeLimit )); } /** @notice Called by the conceptRegistry-contract to create new concepts under it */ function createConcept( address[] memory _parents, uint[] memory _parentFactors, uint _lifetime, bytes memory _data, address _owner, address _cloneOf ) public returns (address) { return address(new ConceptProxy( masterConceptCopy, msg.sender, _parents, _parentFactors, _lifetime, _data, _owner, _cloneOf )); } /** @return bool signalling if address is a contract */ /* solhint-disable no-inline-assembly */ function isContract(address _addr) private view returns (bool) { uint32 size; assembly { size := extcodesize(_addr) } return (size > 0); } /* solhint-enable no-inline-assembly */ }