contract ContractManager is OwnableUpgradeSafe {
    using StringUtils for string;
    using Address for address;

    // mapping of actual smart contracts addresses
    mapping (bytes32 => address) public contracts;

    event ContractUpgraded(string contractsName, address contractsAddress);

    function initialize() external initializer {
        OwnableUpgradeSafe.__Ownable_init();
    }

    /**
     * Adds actual contract to mapping of actual contract addresses
     * @param contractsName - contracts name in skale manager system
     * @param newContractsAddress - contracts address in skale manager system
     */
    function setContractsAddress(string calldata contractsName, address newContractsAddress) external onlyOwner {
        // check newContractsAddress is not equal to zero
        require(newContractsAddress != address(0), "New address is equal zero");
        // create hash of contractsName
        bytes32 contractId = keccak256(abi.encodePacked(contractsName));
        // check newContractsAddress is not equal the previous contract's address
        require(contracts[contractId] != newContractsAddress, "Contract is already added");
        require(newContractsAddress.isContract(), "Given contracts address does not contain code");
        // add newContractsAddress to mapping of actual contract addresses
        contracts[contractId] = newContractsAddress;
        emit ContractUpgraded(contractsName, newContractsAddress);
    }

    function getContract(string calldata name) external view returns (address contractAddress) {
        contractAddress = contracts[keccak256(abi.encodePacked(name))];
        require(contractAddress != address(0), name.strConcat(" contract has not been found"));
    }
}
/**
 * @title Main contract in upgradeable approach. This contract contains the actual
 * current mapping from contract IDs (in the form of human-readable strings) to addresses.
 * @author Artem Payvin
 */
function setContractsAddress(string calldata contractsName, address newContractsAddress) external onlyOwner {
    // check newContractsAddress is not equal to zero
    require(newContractsAddress != address(0), "New address is equal zero");
    // create hash of contractsName
    bytes32 contractId = keccak256(abi.encodePacked(contractsName));
    // check newContractsAddress is not equal the previous contract's address
    require(contracts[contractId] != newContractsAddress, "Contract is already added");
    require(newContractsAddress.isContract(), "Given contracts address does not contain code");
    // add newContractsAddress to mapping of actual contract addresses
    contracts[contractId] = newContractsAddress;
    emit ContractUpgraded(contractsName, newContractsAddress);
}

/**
 * Adds actual contract to mapping of actual contract addresses
 * @param contractsName - contracts name in skale manager system
 * @param newContractsAddress - contracts address in skale manager system
 */