// 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) {
        // Generate a EIP712 typed data hash to compare against the proof.
        return
            SignatureChecker.isValidSignatureNow(
                ADMIN,
                _hashTypedDataV4(
                    keccak256(abi.encode(PROOF_TYPEHASH, _params.recipient, _params.nonce, _id))
                ),
                _proof
            );
    }
}
