// File: src/libraries/AuthManager.sol



/// SPDX-License-Identifier: SSPL-1.-0

/**
 * @custom:org.protocol='mevETH LST Protocol'
 * @custom:org.security='mailto:security@manifoldfinance.com'
 * @custom:org.vcs-commit=$GIT_COMMIT_SHA
 * @custom:org.vendor='CommodityStream, Inc'
 * @custom:org.schema-version="1.0"
 * @custom.org.encryption="manifoldfinance.com/.well-known/pgp-key.asc"
 * @custom:org.preferred-languages="en"
 */

pragma solidity ^0.8.19;

import { IAuth } from "src/interfaces/IAuth.sol";

/// @notice Periphery contract to unify Auth updates across MevEth, MevEthShareVault and WagyuStaker
/// @dev deployment address should be added as admin in initial setup
/// @dev contract addresses are upgradeable. To upgrade auth a redeploy is necessary
contract AuthManager {
    address public immutable auth;
    address public mevEth;
    address public mevEthShareVault;
    address public wagyuStaker;

    error Unauthorized();

    enum Operation {
        ADDADMIN,
        DELETEADMIN,
        ADDOPERATOR,
        DELETEOPERATOR
    }

    /// @notice emitted when MevEthShareVault is a multisig to log missed auth updates
    /// @dev missed updates will need to be manually added when upgrading from a multisig
    event MevEthShareVaultAuthUpdateMissed(address changeAddress, Operation operation);

    constructor(address initialAdmin, address initialMevEth, address initialShareVault, address initialStaker) {
        // auth set one time for safety
        auth = initialAdmin;
        // upgradeable contract addresses
        mevEth = initialMevEth;
        mevEthShareVault = initialShareVault;
        wagyuStaker = initialStaker;
    }

    modifier onlyAuth() {
        if (msg.sender != auth) {
            revert Unauthorized();
        }
        _;
    }

    /**
     * @notice Updates the mevEth address
     * @dev This function is only callable by the authorized address
     * @param newMevEth The new mevEth address
     */
    function updateMevEth(address newMevEth) external onlyAuth {
        mevEth = newMevEth;
    }

    function updateMevEthShareVault(address newMevEthShareVault) external onlyAuth {
        mevEthShareVault = newMevEthShareVault;
    }

    function updateWagyuStaker(address newWagyuStaker) external onlyAuth {
        wagyuStaker = newWagyuStaker;
    }

    /*//////////////////////////////////////////////////////////////
                           Maintenance Functions
    //////////////////////////////////////////////////////////////*/
    /**
     * @notice Adds a new admin to the MevEth, WagyuStaker, and MevEthShareVault contracts.
     * @dev If the MevEthShareVault is a multisig, the `MevEthShareVaultAuthUpdateMissed` event is emitted.
     */
    function addAdmin(address newAdmin) external onlyAuth {
        IAuth(mevEth).addAdmin(newAdmin);
        IAuth(wagyuStaker).addAdmin(newAdmin);
        try IAuth(mevEthShareVault).addAdmin(newAdmin) { }
        catch {
            // handle multisig case
            emit MevEthShareVaultAuthUpdateMissed(newAdmin, Operation.ADDADMIN);
        }
    }

    function deleteAdmin(address oldAdmin) external onlyAuth {
        IAuth(mevEth).deleteAdmin(oldAdmin);
        IAuth(wagyuStaker).deleteAdmin(oldAdmin);
        try IAuth(mevEthShareVault).deleteAdmin(oldAdmin) { }
        catch {
            // handle multisig case
            emit MevEthShareVaultAuthUpdateMissed(oldAdmin, Operation.DELETEADMIN);
        }
    }

    function addOperator(address newOperator) external onlyAuth {
        IAuth(mevEth).addOperator(newOperator);
        IAuth(wagyuStaker).addOperator(newOperator);
        try IAuth(mevEthShareVault).addOperator(newOperator) { }
        catch {
            // handle multisig case
            emit MevEthShareVaultAuthUpdateMissed(newOperator, Operation.ADDOPERATOR);
        }
    }

    function deleteOperator(address oldOperator) external onlyAuth {
        IAuth(mevEth).deleteOperator(oldOperator);
        IAuth(wagyuStaker).deleteOperator(oldOperator);
        try IAuth(mevEthShareVault).deleteOperator(oldOperator) { }
        catch {
            // handle multisig case
            emit MevEthShareVaultAuthUpdateMissed(oldOperator, Operation.DELETEOPERATOR);
        }
    }
}

// File: src/interfaces/IAuth.sol



/// SPDX-License-Identifier: SSPL-1.-0

/**
 * @custom:org.protocol='mevETH LST Protocol'
 * @custom:org.security='mailto:security@manifoldfinance.com'
 * @custom:org.vcs-commit=$GIT_COMMIT_SHA
 * @custom:org.vendor='CommodityStream, Inc'
 * @custom:org.schema-version="1.0"
 * @custom.org.encryption="manifoldfinance.com/.well-known/pgp-key.asc"
 * @custom:org.preferred-languages="en"
 */

pragma solidity ^0.8.19;

interface IAuth {
    event AdminAdded(address indexed newAdmin);
    event AdminDeleted(address indexed oldAdmin);
    event OperatorAdded(address indexed newOperator);
    event OperatorDeleted(address indexed oldOperator);

    /**
     * @notice Adds an admin to the contract.
     * @dev Only existing admins can add new admins.
     */
    function addAdmin(address newAdmin) external;
    /**
     * @notice This function adds a new operator to the contract.
     * @dev This function adds a new operator to the contract. It is only callable by the contract owner. The new operator must be a valid Ethereum address.
     */
    function addOperator(address newOperator) external;
    /**
     * @notice This function is used to check if an address is an admin.
     * @dev This function is used to check if an address is an admin. It takes an address as an argument and returns a boolean value.
     */
    function admins(address) external view returns (bool);
    /**
     * @notice This function is used to delete an admin from the list of admins.
     * @dev This function requires the address of the admin to be deleted. It will delete the admin from the list of admins.
     */
    function deleteAdmin(address oldAdmin) external;
    /**
     * @notice This function is used to delete an operator from the contract.
     * @dev This function is called by the owner of the contract to delete an operator from the contract. The address of the operator to be deleted is passed as
     * an argument.
     */
    function deleteOperator(address oldOperator) external;
    /**
     * @notice This function checks if the given address is an operator.
     * @dev This function is used to check if the given address is an operator. It returns a boolean value indicating whether the address is an operator or not.
     */
    function operators(address) external view returns (bool);
}