// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import { IFaucetAuthModule } from "./IFaucetAuthModule.sol";
import { Faucet } from "../Faucet.sol";

/// @title  AdminFaucetAuthModule
/// @notice FaucetAuthModule that allows an admin to sign off on a given faucet drip. Takes an admin
///         as the constructor argument.
contract AdminFaucetAuthModule is IFaucetAuthModule, EIP712 {
    /// @notice Admin address that can sign off on drips.
    address public immutable ADMIN;

    /// @notice EIP712 typehash for the Proof type.
    bytes32 public constant PROOF_TYPEHASH =
        keccak256("Proof(address recipient,bytes32 nonce,bytes32 id)");

    /// @notice Struct that represents a proof that verifies the admin.
    /// @custom:field recipient Address that will be receiving the faucet funds.
    /// @custom:field nonce     Pseudorandom nonce to prevent replay attacks.
    /// @custom:field id        id for the user requesting the faucet funds.
    struct Proof {
        address recipient;
        bytes32 nonce;
        bytes32 id;
    }

    /// @param _admin   Admin address that can sign off on drips.
    /// @param _name    Contract name.
    /// @param _version The current major version of the signing domain.
    constructor(
        address _admin,
        string memory _name,
        string memory _version
    ) EIP712(_name, _version) {
        ADMIN = _admin;
    }

    /// @inheritdoc IFaucetAuthModule
    function verify(
        Faucet.DripParameters memory _params,
        bytes32 _id,
        bytes memory _proof
    ) external view returns (bool valid_) {
        // Generate a EIP712 typed data hash to compare against the proof.
        valid_ = SignatureChecker.isValidSignatureNow(
            ADMIN,
            _hashTypedDataV4(
                keccak256(abi.encode(PROOF_TYPEHASH, _params.recipient, _params.nonce, _id))
            ),
            _proof
        );
    }
}
