contract AccessControl {

    /// @dev The address of the master administrator account that has the power to
    ///      update itself and all of the other administrator addresses.
    ///      The CEO account is not expected to be used regularly, and is intended to
    ///      be stored offline (i.e. a hardware device kept in a safe).
    address public ceoAddress;

    /// @dev The address of the "day-to-day" operator of various privileged
    ///      functions inside the smart contract. Although the CEO has the power
    ///      to replace the COO, the CEO address doesn't actually have the power
    ///      to do "COO-only" operations. This is to discourage the regular use
    ///      of the CEO account.
    address public cooAddress;

    /// @dev The address that is allowed to move money around. Kept separate from
    ///      the COO because the COO address typically lives on an internet-connected
    ///      computer.
    address payable public cfoAddress;

    // Events to indicate when access control role addresses are updated.
    event CEOTransferred(address previousCeo, address newCeo);
    event COOTransferred(address previousCoo, address newCoo);
    event CFOTransferred(address previousCfo, address newCfo);

    /// @dev The AccessControl constructor sets the `ceoAddress` to the sender account. Also
    ///      initializes the COO and CFO to the passed values (CFO is optional and can be address(0)).
    /// @param newCooAddress The initial COO address to set
    /// @param newCfoAddress The initial CFO to set (optional)
    constructor(address newCooAddress, address payable newCfoAddress) public {
        _setCeo(msg.sender);
        setCoo(newCooAddress);

        if (newCfoAddress != address(0)) {
            setCfo(newCfoAddress);
        }
    }

    /// @notice Access modifier for CEO-only functionality
    modifier onlyCEO() {
        require(msg.sender == ceoAddress, "Only CEO");
        _;
    }

    /// @notice Access modifier for COO-only functionality
    modifier onlyCOO() {
        require(msg.sender == cooAddress, "Only COO");
        _;
    }

    /// @notice Access modifier for CFO-only functionality
    modifier onlyCFO() {
        require(msg.sender == cfoAddress, "Only CFO");
        _;
    }

    function checkControlAddress(address newController) internal view {
        require(newController != address(0) && newController != ceoAddress, "Invalid CEO address");
    }

    /// @notice Assigns a new address to act as the CEO. Only available to the current CEO.
    /// @param newCeo The address of the new CEO
    function setCeo(address newCeo) external onlyCEO {
        checkControlAddress(newCeo);
        _setCeo(newCeo);
    }

    /// @dev An internal utility function that updates the CEO variable and emits the
    ///      transfer event. Used from both the public setCeo function and the constructor.
    function _setCeo(address newCeo) private {
        emit CEOTransferred(ceoAddress, newCeo);
        ceoAddress = newCeo;
    }

    /// @notice Assigns a new address to act as the COO. Only available to the current CEO.
    /// @param newCoo The address of the new COO
    function setCoo(address newCoo) public onlyCEO {
        checkControlAddress(newCoo);
        emit COOTransferred(cooAddress, newCoo);
        cooAddress = newCoo;
    }

    /// @notice Assigns a new address to act as the CFO. Only available to the current CEO.
    /// @param newCfo The address of the new CFO
    function setCfo(address payable newCfo) public onlyCEO {
        checkControlAddress(newCfo);
        emit CFOTransferred(cfoAddress, newCfo);
        cfoAddress = newCfo;
    }
}
/// @title Contract that manages addresses and access modifiers for certain operations.
/// @author Dapper Labs Inc. (https://www.dapperlabs.com)
function setCfo(address payable newCfo) public onlyCEO {
    checkControlAddress(newCfo);
    emit CFOTransferred(cfoAddress, newCfo);
    cfoAddress = newCfo;
}

/// @notice Assigns a new address to act as the CFO. Only available to the current CEO.
/// @param newCfo The address of the new CFO