interface IProxyManagerAccessControl {
/* ==========  Events  ========== */

  event AdminAccessGranted(address newAdmin);
  event AdminAccessRevoked(address newAdmin);

/* ==========  Queries  ========== */
  /**
   * @dev Checks whether `account` has administrator access.
   */
  function hasAdminAccess(address account) external view returns (bool);

  /**
   * @dev Gets the address of the proxy manager.
   */
  function proxyManager() external view returns (address);

/* ==========  Controls  ========== */

  /**
   * @dev Allows `deployer` to deploy many-to-one proxies.
   */
  function approveDeployer(address deployer) external;

  /**
   * @dev Prevents `deployer` from deploying many-to-one proxies.
   */
  function revokeDeployerApproval(address deployer) external;

  /**
   * @dev Grants admin access to `admin`.
   */
  function grantAdminAccess(address admin) external;

  /**
   * @dev Revokes admin access from `admin`.
   */
  function revokeAdminAccess(address admin) external;

  /**
   * @dev Transfers ownership of the proxy manager.
   */
  function transferManagerOwnership(address newOwner) external;

/* ==========  Implementation Management  ========== */

  /**
   * @dev Creates a many-to-one proxy relationship.
   *
   * Deploys an implementation holder contract which stores the
   * implementation address for many proxies. The implementation
   * address can be updated on the holder to change the runtime
   * code used by all its proxies.
   *
   * @param implementationID ID for the implementation, used to identify the
   * proxies that use it. Also used as the salt in the create2 call when
   * deploying the implementation holder contract.
   * @param implementation Address with the runtime code the proxies
   * should use.
   */
  function createManyToOneProxyRelationship(
    bytes32 implementationID,
    address implementation
  ) external;

  /**
   * @dev Lock the current implementation for `proxyAddress` so that it can never be upgraded again.
   */
  function lockImplementationManyToOne(bytes32 implementationID) external;

  /**
   * @dev Lock the current implementation for `proxyAddress` so that it can never be upgraded again.
   */
  function lockImplementationOneToOne(address proxyAddress) external;

  /**
   * @dev Updates the implementation address for a many-to-one
   * proxy relationship.
   *
   * @param implementationID Identifier for the implementation.
   * @param implementation Address with the runtime code the proxies
   * should use.
   */
  function setImplementationAddressManyToOne(
    bytes32 implementationID,
    address implementation
  ) external;

  /**
   * @dev Updates the implementation address for a one-to-one proxy.
   *
   * Note: This could work for many-to-one as well if the caller
   * provides the implementation holder address in place of the
   * proxy address, as they use the same access control and update
   * mechanism.
   *
   * @param proxyAddress Address of the deployed proxy
   * @param implementation Address with the runtime code for
   * the proxy to use.
   */
  function setImplementationAddressOneToOne(
    address proxyAddress,
    address implementation
  ) external;

  /* ==========  Proxy Deployment  ========== */

  /**
   * @dev Deploy a proxy contract with a one-to-one relationship
   * with its implementation.
   *
   * The proxy will have its own implementation address which can
   * be updated by the proxy manager.
   *
   * @param suppliedSalt Salt provided by the account requesting deployment.
   * @param implementation Address of the contract with the runtime
   * code that the proxy should use.
   */
  function deployProxyOneToOne(
    bytes32 suppliedSalt,
    address implementation
  ) external returns(address proxyAddress);

  /**
   * @dev Deploy a proxy with a many-to-one relationship with its implemenation.
   *
   * The proxy will call the implementation holder for every transaction to
   * determine the address to use in calls.
   *
   * @param implementationID Identifier for the proxy's implementation.
   * @param suppliedSalt Salt provided by the account requesting deployment.
   */
  function deployProxyManyToOne(
    bytes32 implementationID,
    bytes32 suppliedSalt
  ) external returns(address proxyAddress);
}
function createManyToOneProxyRelationship(
  bytes32 implementationID,
  address implementation
) external;

/**
 * @dev Creates a many-to-one proxy relationship.
 *
 * Deploys an implementation holder contract which stores the
 * implementation address for many proxies. The implementation
 * address can be updated on the holder to change the runtime
 * code used by all its proxies.
 *
 * @param implementationID ID for the implementation, used to identify the
 * proxies that use it. Also used as the salt in the create2 call when
 * deploying the implementation holder contract.
 * @param implementation Address with the runtime code the proxies
 * should use.
 */