Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
3d4019d6
Commit
3d4019d6
authored
May 05, 2023
by
tre
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Address comments and split AuthModule into separate file
parent
5943c418
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
366 additions
and
207 deletions
+366
-207
AdminFaucetAuthModule.t.sol
...phery/contracts/foundry-tests/AdminFaucetAuthModule.t.sol
+185
-0
Faucet.t.sol
.../contracts-periphery/contracts/foundry-tests/Faucet.t.sol
+37
-33
FaucetHelper.sol
...acts-periphery/contracts/testing/helpers/FaucetHelper.sol
+11
-17
Faucet.sol
...contracts-periphery/contracts/universal/faucet/Faucet.sol
+38
-157
AdminFaucetAuthModule.sol
...ts/universal/faucet/authmodules/AdminFaucetAuthModule.sol
+72
-0
IFaucetAuthModule.sol
...tracts/universal/faucet/authmodules/IFaucetAuthModule.sol
+23
-0
No files found.
packages/contracts-periphery/contracts/foundry-tests/AdminFaucetAuthModule.t.sol
0 → 100644
View file @
3d4019d6
//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
);
}
}
packages/contracts-periphery/contracts/foundry-tests/Faucet.t.sol
View file @
3d4019d6
...
@@ -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;
AdminF
AM
adminFam;
AdminF
aucetAuthModule
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 AdminF
AM
(faucetAuthAdmin);
adminFam = new AdminF
aucetAuthModule
(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)
);
}
}
}
}
packages/contracts-periphery/contracts/testing/helpers/FaucetHelper.sol
View file @
3d4019d6
//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(AdminF
AM
.Proof memory _proof)
function getProofStructHash(AdminF
aucetAuthModule
.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(
AdminF
AM
.Proof memory _proof,
AdminF
aucetAuthModule
.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));
}
}
}
}
packages/contracts-periphery/contracts/universal/faucet/Faucet.sol
View file @
3d4019d6
// 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;
I
FaucetAuthModule 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
(I
FaucetAuthModule => 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);
}
}
}
}
packages/contracts-periphery/contracts/universal/faucet/authmodules/AdminFaucetAuthModule.sol
0 → 100644
View file @
3d4019d6
// 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);
}
}
packages/contracts-periphery/contracts/universal/faucet/authmodules/IFaucetAuthModule.sol
0 → 100644
View file @
3d4019d6
// 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);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment