Commit 3d4019d6 authored by tre's avatar tre

Address comments and split AuthModule into separate file

parent 5943c418
//SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
import { AdminFaucetAuthModule } from "../universal/faucet/authmodules/AdminFaucetAuthModule.sol";
import { Faucet } from "../universal/faucet/Faucet.sol";
import { FaucetHelper } from "../testing/helpers/FaucetHelper.sol";
/**
* @title AdminFaucetAuthModuleTest
* @notice Tests the AdminFaucetAuthModule contract.
*/
contract AdminFaucetAuthModuleTest is Test {
/**
* @notice The admin of the `AdminFaucetAuthModule` contract.
*/
address internal admin;
/**
* @notice Private key of the `admin`.
*/
uint256 internal adminKey;
/**
* @notice Not an admin of the `AdminFaucetAuthModule` contract.
*/
address internal nonAdmin;
/**
* @notice Private key of the `nonAdmin`.
*/
uint256 internal nonAdminKey;
/**
* @notice An instance of the `AdminFaucetAuthModule` contract.
*/
AdminFaucetAuthModule adminFam;
/**
* @notice An instance of the `FaucetHelper` contract.
*/
FaucetHelper faucetHelper;
/**
* @notice Deploy the `AdminFaucetAuthModule` contract.
*/
function setUp() external {
adminKey = 0xB0B0B0B0;
admin = vm.addr(adminKey);
nonAdminKey = 0xC0C0C0C0;
nonAdmin = vm.addr(nonAdminKey);
adminFam = new AdminFaucetAuthModule(admin);
adminFam.initialize("AdminFAM");
faucetHelper = new FaucetHelper();
}
/**
* @notice Get signature as a bytes blob.
*
*/
function _getSignature(uint256 _signingPrivateKey, bytes32 _digest)
internal
pure
returns (bytes memory)
{
(uint8 v, bytes32 r, bytes32 s) = vm.sign(_signingPrivateKey, _digest);
bytes memory signature = abi.encodePacked(r, s, v);
return signature;
}
/**
* @notice Signs a proof with the given private key and returns the signature using
* the given EIP712 domain separator. This assumes that the issuer's address is the
* corresponding public key to _issuerPrivateKey.
*/
function issueProofWithEIP712Domain(
uint256 _issuerPrivateKey,
bytes memory _eip712Name,
bytes memory _contractVersion,
uint256 _eip712Chainid,
address _eip712VerifyingContract,
address recipient,
bytes memory id,
bytes32 nonce
) internal view returns (bytes memory) {
AdminFaucetAuthModule.Proof memory proof = AdminFaucetAuthModule.Proof(
recipient,
nonce,
id
);
return
_getSignature(
_issuerPrivateKey,
faucetHelper.getDigestWithEIP712Domain(
proof,
_eip712Name,
_contractVersion,
_eip712Chainid,
_eip712VerifyingContract
)
);
}
/**
* @notice assert that verify returns true for valid proofs signed by admins.
*/
function test_adminProof_verify_returnsTrue() external {
bytes32 nonce = faucetHelper.consumeNonce();
address fundsReceiver = makeAddr("fundsReceiver");
bytes memory proof = issueProofWithEIP712Domain(
adminKey,
bytes("AdminFAM"),
bytes(adminFam.version()),
block.chainid,
address(adminFam),
fundsReceiver,
abi.encodePacked(fundsReceiver),
nonce
);
vm.prank(nonAdmin);
adminFam.verify(
Faucet.DripParameters(payable(fundsReceiver), nonce),
abi.encodePacked(fundsReceiver),
proof
);
}
/**
* @notice assert that verify returns false for proofs signed by nonadmins.
*/
function test_nonAdminProof_verify_returnsFalse() external {
bytes32 nonce = faucetHelper.consumeNonce();
address fundsReceiver = makeAddr("fundsReceiver");
bytes memory proof = issueProofWithEIP712Domain(
nonAdminKey,
bytes("AdminFAM"),
bytes(adminFam.version()),
block.chainid,
address(adminFam),
fundsReceiver,
abi.encodePacked(fundsReceiver),
nonce
);
vm.prank(admin);
assertEq(
adminFam.verify(
Faucet.DripParameters(payable(fundsReceiver), nonce),
abi.encodePacked(fundsReceiver),
proof
),
false
);
}
/**
* @notice assert that verify returns false for proofs where the id in the proof is different
* than the id in the call to verify.
*/
function test_proofWithWrongId_verify_returnsFalse() external {
bytes32 nonce = faucetHelper.consumeNonce();
address fundsReceiver = makeAddr("fundsReceiver");
address randomAddress = makeAddr("randomAddress");
bytes memory proof = issueProofWithEIP712Domain(
adminKey,
bytes("AdminFAM"),
bytes(adminFam.version()),
block.chainid,
address(adminFam),
fundsReceiver,
abi.encodePacked(fundsReceiver),
nonce
);
vm.prank(admin);
assertEq(
adminFam.verify(
Faucet.DripParameters(payable(fundsReceiver), nonce),
abi.encodePacked(randomAddress),
proof
),
false
);
}
}
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { AdminFAM, Faucet } from "../universal/faucet/Faucet.sol"; import { Faucet } from "../universal/faucet/Faucet.sol";
import { AdminFaucetAuthModule } from "../universal/faucet/authmodules/AdminFaucetAuthModule.sol";
import { FaucetHelper } from "../testing/helpers/FaucetHelper.sol"; import { FaucetHelper } from "../testing/helpers/FaucetHelper.sol";
contract Faucet_Initializer is Test { contract Faucet_Initializer is Test {
...@@ -14,7 +15,7 @@ contract Faucet_Initializer is Test { ...@@ -14,7 +15,7 @@ contract Faucet_Initializer is Test {
uint256 internal nonAdminKey; uint256 internal nonAdminKey;
Faucet faucet; Faucet faucet;
AdminFAM adminFam; AdminFaucetAuthModule adminFam;
FaucetHelper faucetHelper; FaucetHelper faucetHelper;
...@@ -31,7 +32,7 @@ contract Faucet_Initializer is Test { ...@@ -31,7 +32,7 @@ contract Faucet_Initializer is Test {
_initializeContracts(); _initializeContracts();
} }
/** /**
* @notice Instantiates a Faucet. * @notice Instantiates a Faucet.
*/ */
function _initializeContracts() internal { function _initializeContracts() internal {
...@@ -40,19 +41,18 @@ contract Faucet_Initializer is Test { ...@@ -40,19 +41,18 @@ contract Faucet_Initializer is Test {
// Fill faucet with ether. // Fill faucet with ether.
vm.deal(address(faucet), 10 ether); vm.deal(address(faucet), 10 ether);
adminFam = new AdminFAM(faucetAuthAdmin); adminFam = new AdminFaucetAuthModule(faucetAuthAdmin);
adminFam.initialize("AdminFAM"); adminFam.initialize("AdminFAM");
faucetHelper = new FaucetHelper(); faucetHelper = new FaucetHelper();
} }
function _enableFaucetAuthModule() internal { function _enableFaucetAuthModule() internal {
vm.prank(faucetContractAdmin); vm.prank(faucetContractAdmin);
faucet.configure(adminFam, Faucet.ModuleConfig(true, 1 days, 1 ether)); faucet.configure(adminFam, Faucet.ModuleConfig("OptimistModule", true, 1 days, 1 ether));
} }
/** /**
* @notice Get signature as a bytes blob. * @notice Get signature as a bytes blob.
* *
*/ */
...@@ -82,7 +82,11 @@ contract Faucet_Initializer is Test { ...@@ -82,7 +82,11 @@ contract Faucet_Initializer is Test {
bytes memory id, bytes memory id,
bytes32 nonce bytes32 nonce
) internal view returns (bytes memory) { ) internal view returns (bytes memory) {
AdminFAM.Proof memory proof = AdminFAM.Proof(recipient, nonce, id); AdminFaucetAuthModule.Proof memory proof = AdminFaucetAuthModule.Proof(
recipient,
nonce,
id
);
return return
_getSignature( _getSignature(
_issuerPrivateKey, _issuerPrivateKey,
...@@ -105,43 +109,43 @@ contract FaucetTest is Faucet_Initializer { ...@@ -105,43 +109,43 @@ contract FaucetTest is Faucet_Initializer {
function test_AuthAdmin_drip_succeeds() external { function test_AuthAdmin_drip_succeeds() external {
_enableFaucetAuthModule(); _enableFaucetAuthModule();
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
bytes memory signature bytes memory signature = issueProofWithEIP712Domain(
= issueProofWithEIP712Domain( faucetAuthAdminKey,
faucetAuthAdminKey, bytes("AdminFAM"),
bytes("AdminFAM"), bytes(adminFam.version()),
bytes(adminFam.version()), block.chainid,
block.chainid, address(adminFam),
address(adminFam), fundsReceiver,
fundsReceiver, abi.encodePacked(fundsReceiver),
abi.encodePacked(fundsReceiver), nonce
nonce );
);
vm.prank(nonAdmin); vm.prank(nonAdmin);
faucet.drip( faucet.drip(
Faucet.DripParameters(payable(fundsReceiver), nonce), Faucet.DripParameters(payable(fundsReceiver), nonce),
Faucet.AuthParameters(adminFam, abi.encodePacked(fundsReceiver), signature)); Faucet.AuthParameters(adminFam, abi.encodePacked(fundsReceiver), signature)
);
} }
function test_nonAdmin_drip_fails() external { function test_nonAdmin_drip_fails() external {
_enableFaucetAuthModule(); _enableFaucetAuthModule();
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
bytes memory signature bytes memory signature = issueProofWithEIP712Domain(
= issueProofWithEIP712Domain( nonAdminKey,
nonAdminKey, bytes("AdminFAM"),
bytes("AdminFAM"), bytes(adminFam.version()),
bytes(adminFam.version()), block.chainid,
block.chainid, address(adminFam),
address(adminFam), fundsReceiver,
fundsReceiver, abi.encodePacked(fundsReceiver),
abi.encodePacked(fundsReceiver), nonce
nonce );
);
vm.prank(nonAdmin); vm.prank(nonAdmin);
vm.expectRevert("Faucet: drip parameters could not be verified by security module"); vm.expectRevert("Faucet: drip parameters could not be verified by security module");
faucet.drip( faucet.drip(
Faucet.DripParameters(payable(fundsReceiver), nonce), Faucet.DripParameters(payable(fundsReceiver), nonce),
Faucet.AuthParameters(adminFam, abi.encodePacked(fundsReceiver), signature)); Faucet.AuthParameters(adminFam, abi.encodePacked(fundsReceiver), signature)
);
} }
} }
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { AdminFAM } from "../../universal/faucet/Faucet.sol"; import {
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; AdminFaucetAuthModule
} from "../../universal/faucet/authmodules/AdminFaucetAuthModule.sol";
import {
ECDSAUpgradeable
} from "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
/** /**
* Simple helper contract that helps with testing the Faucet contract. * Simple helper contract that helps with testing the Faucet contract.
...@@ -44,23 +48,15 @@ contract FaucetHelper { ...@@ -44,23 +48,15 @@ contract FaucetHelper {
* *
* @return EIP-712 typed struct hash. * @return EIP-712 typed struct hash.
*/ */
function getProofStructHash(AdminFAM.Proof memory _proof) function getProofStructHash(AdminFaucetAuthModule.Proof memory _proof)
public public
pure pure
returns (bytes32) returns (bytes32)
{ {
return return keccak256(abi.encode(PROOF_TYPEHASH, _proof.recipient, _proof.nonce, _proof.id));
keccak256(
abi.encode(
PROOF_TYPEHASH,
_proof.recipient,
_proof.nonce,
_proof.id
)
);
} }
/** /**
* @notice Computes the EIP712 digest with the given domain parameters. * @notice Computes the EIP712 digest with the given domain parameters.
* Used for testing that different domain parameters fail. * Used for testing that different domain parameters fail.
* *
...@@ -75,7 +71,7 @@ contract FaucetHelper { ...@@ -75,7 +71,7 @@ contract FaucetHelper {
* @return EIP-712 compatible digest. * @return EIP-712 compatible digest.
*/ */
function getDigestWithEIP712Domain( function getDigestWithEIP712Domain(
AdminFAM.Proof memory _proof, AdminFaucetAuthModule.Proof memory _proof,
bytes memory _name, bytes memory _name,
bytes memory _version, bytes memory _version,
uint256 _chainid, uint256 _chainid,
...@@ -90,8 +86,6 @@ contract FaucetHelper { ...@@ -90,8 +86,6 @@ contract FaucetHelper {
_verifyingContract _verifyingContract
) )
); );
return return ECDSAUpgradeable.toTypedDataHash(domainSeparator, getProofStructHash(_proof));
ECDSA.toTypedDataHash(domainSeparator, getProofStructHash(_proof));
} }
} }
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol"; import { IFaucetAuthModule } from "./authmodules/IFaucetAuthModule.sol";
import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import {
EIP712Upgradeable
} from "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";
/** /**
* @title SafeSend * @title SafeSend
...@@ -13,110 +9,10 @@ import { ...@@ -13,110 +9,10 @@ import {
*/ */
contract SafeSend { contract SafeSend {
/** /**
* @param recipient Account to send ETH to. * @param _recipient Account to send ETH to.
*/ */
constructor( constructor(address payable _recipient) payable {
address payable recipient selfdestruct(_recipient);
)
payable
{
selfdestruct(recipient);
}
}
/**
* @title FaucetAuthModule
* @notice Interface for faucet authentication modules.
*/
interface FaucetAuthModule {
/**
* @notice Verifies that the given drip parameters are valid.
*
* @param params Drip parameters to verify.
* @param id Authentication ID to verify.
* @param proof Authentication proof to verify.
*/
function verify(
Faucet.DripParameters memory params,
bytes memory id,
bytes memory proof
)
external
view
returns (
bool
);
}
/**
* @title AdminFAM
* @notice FaucetAuthModule that allows an admin to sign off on a given faucet drip. Takes an admin
* as the constructor argument.
*/
contract AdminFAM is FaucetAuthModule, Semver, EIP712Upgradeable {
/**
* @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,bytes 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;
bytes id;
}
/**
* @param admin Admin address that can sign off on drips.
*/
constructor(
address admin
) Semver(1, 0, 0) {
ADMIN = admin;
}
/**
* @notice Initializes this contract, setting the EIP712 context.
*
* @param _name Contract name.
*/
function initialize(string memory _name) public initializer {
__EIP712_init(_name, version());
}
/**
* @inheritdoc FaucetAuthModule
*/
function verify(
Faucet.DripParameters memory params,
bytes memory id,
bytes memory proof
) external view returns (bool) {
// Generate a EIP712 typed data hash to compare against the proof.
bytes32 digest = _hashTypedDataV4(
keccak256(
abi.encode(
PROOF_TYPEHASH,
params.recipient,
params.nonce,
id
)
)
);
return SignatureChecker.isValidSignatureNow(ADMIN, digest, proof);
} }
} }
...@@ -137,7 +33,7 @@ contract Faucet { ...@@ -137,7 +33,7 @@ contract Faucet {
* @notice Parameters for authentication. * @notice Parameters for authentication.
*/ */
struct AuthParameters { struct AuthParameters {
FaucetAuthModule module; IFaucetAuthModule module;
bytes id; bytes id;
bytes proof; bytes proof;
} }
...@@ -146,6 +42,7 @@ contract Faucet { ...@@ -146,6 +42,7 @@ contract Faucet {
* @notice Configuration for an authentication module. * @notice Configuration for an authentication module.
*/ */
struct ModuleConfig { struct ModuleConfig {
string name;
bool enabled; bool enabled;
uint256 ttl; uint256 ttl;
uint256 amount; uint256 amount;
...@@ -159,115 +56,99 @@ contract Faucet { ...@@ -159,115 +56,99 @@ contract Faucet {
/** /**
* @notice Mapping of authentication modules to their configurations. * @notice Mapping of authentication modules to their configurations.
*/ */
mapping (FaucetAuthModule => ModuleConfig) public modules; mapping(IFaucetAuthModule => ModuleConfig) public modules;
/** /**
* @notice Mapping of authentication IDs to the next timestamp at which they can be used. * @notice Mapping of authentication IDs to the next timestamp at which they can be used.
*/ */
mapping (FaucetAuthModule => mapping (bytes => uint256)) public timeouts; mapping(IFaucetAuthModule => mapping(bytes => uint256)) public timeouts;
/** /**
* @notice Maps from id to nonces to whether or not they have been used. * @notice Maps from id to nonces to whether or not they have been used.
*/ */
mapping(bytes => mapping(bytes32 => bool)) public usedNonces; mapping(bytes => mapping(bytes32 => bool)) public usedNonces;
/** /**
* @notice Modifier that makes a function admin priviledged. * @notice Modifier that makes a function admin priviledged.
*/ */
modifier priviledged() { modifier priviledged() {
require( require(msg.sender == ADMIN, "Faucet: function can only be called by admin");
msg.sender == ADMIN, _;
"Faucet: function can only be called by admin"
);
_;
} }
/** /**
* @param admin Admin address that can configure the faucet. * @param _admin Admin address that can configure the faucet.
*/ */
constructor( constructor(address _admin) {
address admin ADMIN = _admin;
) {
ADMIN = admin;
} }
/** /**
* @notice Allows users to donate ETH to this contract. * @notice Allows users to donate ETH to this contract.
*/ */
receive() external payable { receive() external payable {
// Thank you! // Thank you!
} }
/** /**
* @notice Allows the admin to withdraw funds. * @notice Allows the admin to withdraw funds.
* *
* @param recipient Address to receive the funds. * @param _recipient Address to receive the funds.
* @param amount Amount of ETH in wei to withdraw. * @param _amount Amount of ETH in wei to withdraw.
*/ */
function withdraw( function withdraw(address payable _recipient, uint256 _amount) public priviledged {
address payable recipient, new SafeSend{ value: _amount }(_recipient);
uint256 amount }
) public priviledged {
new SafeSend{value: amount}(recipient);
}
/** /**
* @notice Allows the admin to configure an authentication module. * @notice Allows the admin to configure an authentication module.
* *
* @param module Authentication module to configure. * @param _module Authentication module to configure.
* @param config Configuration to set for the module. * @param _config Configuration to set for the module.
*/ */
function configure( function configure(IFaucetAuthModule _module, ModuleConfig memory _config) public priviledged {
FaucetAuthModule module, modules[_module] = _config;
ModuleConfig memory config
) public priviledged {
modules[module] = config;
} }
/** /**
* @notice Drips ETH to a recipient account. * @notice Drips ETH to a recipient account.
* *
* @param params Drip parameters. * @param _params Drip parameters.
* @param auth Authentication parameters. * @param _auth Authentication parameters.
*/ */
function drip( function drip(DripParameters memory _params, AuthParameters memory _auth) public {
DripParameters memory params, // Grab the module config once.
AuthParameters memory auth ModuleConfig memory config = modules[_auth.module];
) public {
// Grab the module config once.
ModuleConfig memory config = modules[auth.module];
// Make sure we're using a supported security module. // Make sure we're using a supported security module.
require( require(config.enabled, "Faucet: provided auth module is not supported by this faucet");
config.enabled,
"Faucet: provided auth module is not supported by this faucet"
);
// The issuer's signature commits to a nonce to prevent replay attacks. // The issuer's signature commits to a nonce to prevent replay attacks.
// This checks that the nonce has not been used for this issuer before. The nonces are // This checks that the nonce has not been used for this issuer before. The nonces are
// scoped to the issuer address, so the same nonce can be used by different issuers without // scoped to the issuer address, so the same nonce can be used by different issuers without
// clashing. // clashing.
require( require(
usedNonces[auth.id][params.nonce] == false, usedNonces[_auth.id][_params.nonce] == false,
"Faucet: nonce has already been used" "Faucet: nonce has already been used"
); );
// Make sure the timeout has elapsed. // Make sure the timeout has elapsed.
require( require(
timeouts[auth.module][auth.id] < block.timestamp, timeouts[_auth.module][_auth.id] == 0 ||
timeouts[_auth.module][_auth.id] > block.timestamp,
"Faucet: auth cannot be used yet because timeout has not elapsed" "Faucet: auth cannot be used yet because timeout has not elapsed"
); );
// Verify the proof. // Verify the proof.
require( require(
auth.module.verify(params, auth.id, auth.proof), _auth.module.verify(_params, _auth.id, _auth.proof),
"Faucet: drip parameters could not be verified by security module" "Faucet: drip parameters could not be verified by security module"
); );
// Set the next timestamp at which this auth id can be used. // Set the next timestamp at which this auth id can be used.
timeouts[auth.module][auth.id] = block.timestamp + config.ttl; timeouts[_auth.module][_auth.id] = block.timestamp + config.ttl;
// Execute a safe transfer of ETH to the recipient account. // Execute a safe transfer of ETH to the recipient account.
new SafeSend{value: config.amount}(params.recipient); new SafeSend{ value: config.amount }(_params.recipient);
} }
} }
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol";
import {
EIP712Upgradeable
} from "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.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, Semver, EIP712Upgradeable {
/**
* @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,bytes 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;
bytes id;
}
/**
* @param admin Admin address that can sign off on drips.
*/
constructor(address admin) Semver(1, 0, 0) {
ADMIN = admin;
}
/**
* @notice Initializes this contract, setting the EIP712 context.
*
* @param _name Contract name.
*/
function initialize(string memory _name) public initializer {
__EIP712_init(_name, version());
}
/**
* @inheritdoc IFaucetAuthModule
*/
function verify(
Faucet.DripParameters memory _params,
bytes memory _id,
bytes memory _proof
) external view returns (bool) {
// Generate a EIP712 typed data hash to compare against the proof.
bytes32 digest = _hashTypedDataV4(
keccak256(abi.encode(PROOF_TYPEHASH, _params.recipient, _params.nonce, _id))
);
return SignatureChecker.isValidSignatureNow(ADMIN, digest, _proof);
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Faucet } from "../Faucet.sol";
/**
* @title IFaucetAuthModule
* @notice Interface for faucet authentication modules.
*/
interface IFaucetAuthModule {
/**
* @notice Verifies that the given drip parameters are valid.
*
* @param _params Drip parameters to verify.
* @param _id Authentication ID to verify.
* @param _proof Authentication proof to verify.
*/
function verify(
Faucet.DripParameters memory _params,
bytes memory _id,
bytes memory _proof
) external view returns (bool);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment