mirror of
https://github.com/zkemail/zk-email-verify.git
synced 2026-01-08 21:18:09 -05:00
Add UserOverrideableDKIMRegistry.sol. (#199)
* Add UserOverrideableDKIMRegistry.sol. * Bump the version. * Update UserOverrideableDKIMRegistry.sol * Update testcases for UserOverrideableDKIMRegistry.sol. * Update version to 6.1.2. * Remove unused function. * Change the default argument of isDKIMPublicKeyHashValid and add reactivateDKIMPublicKeyHash * Add test for reactivate function and fix failed testcases. * Add test cases using signature for reactivateDKIMPublicKeyHash function. --------- Co-authored-by: SoraSuegami <suegamisora@gmail.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "6.1.1",
|
||||
"version": "6.1.2",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zk-email/circuits",
|
||||
"version": "6.1.1",
|
||||
"version": "6.1.2",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"publish": "yarn npm publish --access=public",
|
||||
|
||||
@@ -16,6 +16,13 @@
|
||||
For a detailed overview of its functionalities, please refer to the source file: [DKIMRegistry.sol](./DKIMRegistry.sol)
|
||||
</details>
|
||||
|
||||
## UserOverrideableDKIMRegistry.sol
|
||||
|
||||
`UserOverrideableDKIMRegistry.sol` is a Solidity contract within the `@zk-email/contracts` package.
|
||||
This functions similarly to [DKIMRegistry](./DKIMRegistry.sol), but it allows users to set their own public keys. Even if the main authorizer, who is the contract owner, has already approved a public key, the user's signature is still required for setting it. Additionally, the public key can be revoked by the signature of either the user or the main authorizer alone.
|
||||
|
||||
[UserOverrideableDKIMRegistry.sol](./UserOverrideableDKIMRegistry.sol)
|
||||
|
||||
## StringUtils.sol
|
||||
|
||||
`StringUtils.sol` is a Solidity library that offers a range of string manipulation functions, including conversion between bytes and strings, and numerical string operations, for use across the `@zk-email/contracts` package.
|
||||
|
||||
358
packages/contracts/UserOverrideableDKIMRegistry.sol
Normal file
358
packages/contracts/UserOverrideableDKIMRegistry.sol
Normal file
@@ -0,0 +1,358 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "./interfaces/IDKIMRegistry.sol";
|
||||
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
||||
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
|
||||
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
|
||||
import "@openzeppelin/contracts/utils/Strings.sol";
|
||||
|
||||
/**
|
||||
A Registry that store the hash(dkim_public_key) for each domain
|
||||
The hash is calculated by taking Poseidon of DKIM key split into 9 chunks of 242 bits each
|
||||
|
||||
https://zkrepl.dev/?gist=43ce7dce2466c63812f6efec5b13aa73 can be used to generate the public key hash.
|
||||
The same code is used in EmailVerifier.sol
|
||||
Input is DKIM pub key split into 17 chunks of 121 bits. You can use `helpers` package to fetch/split DKIM keys
|
||||
*/
|
||||
contract UserOverrideableDKIMRegistry is IDKIMRegistry, Ownable {
|
||||
using Strings for *;
|
||||
using ECDSA for *;
|
||||
|
||||
event DKIMPublicKeyHashRegistered(
|
||||
string domainName,
|
||||
bytes32 publicKeyHash,
|
||||
address register
|
||||
);
|
||||
event DKIMPublicKeyHashRevoked(bytes32 publicKeyHash, address register);
|
||||
event DKIMPublicKeyHashReactivated(bytes32 publicKeyHash, address register);
|
||||
|
||||
// Main authorizer address.
|
||||
address public mainAuthorizer;
|
||||
|
||||
// Mapping from domain name to DKIM public key hash
|
||||
mapping(string => mapping(bytes32 => mapping(address => bool)))
|
||||
public dkimPublicKeyHashes;
|
||||
|
||||
// DKIM public that are revoked (eg: in case of private key compromise)
|
||||
mapping(bytes32 => mapping(address => bool))
|
||||
public revokedDKIMPublicKeyHashes;
|
||||
|
||||
// DKIM public that are reactivated (eg: in case that a malicious `mainAuthorizer` revokes a valid public key but a user reactivates it.)
|
||||
mapping(bytes32 => mapping(address => bool))
|
||||
public reactivatedDKIMPublicKeyHashes;
|
||||
|
||||
string public constant SET_PREFIX = "SET:";
|
||||
string public constant REVOKE_PREFIX = "REVOKE:";
|
||||
string public constant REACTIVATE_PREFIX = "REACTIVATE";
|
||||
|
||||
constructor(address _owner, address _mainAuthorizer) Ownable(_owner) {
|
||||
mainAuthorizer = _mainAuthorizer;
|
||||
}
|
||||
|
||||
function isDKIMPublicKeyHashValid(
|
||||
string memory domainName,
|
||||
bytes32 publicKeyHash
|
||||
) public view returns (bool) {
|
||||
address ownerOfSender = Ownable(msg.sender).owner();
|
||||
return
|
||||
isDKIMPublicKeyHashValid(domainName, publicKeyHash, ownerOfSender);
|
||||
}
|
||||
|
||||
function isDKIMPublicKeyHashValid(
|
||||
string memory domainName,
|
||||
bytes32 publicKeyHash,
|
||||
address authorizer
|
||||
) public view returns (bool) {
|
||||
require(bytes(domainName).length > 0, "domain name cannot be zero");
|
||||
require(publicKeyHash != bytes32(0), "public key hash cannot be zero");
|
||||
require(authorizer != address(0), "authorizer address cannot be zero");
|
||||
uint256 revokeThreshold = _computeRevokeThreshold(
|
||||
publicKeyHash,
|
||||
authorizer
|
||||
);
|
||||
uint256 setThreshold = _computeSetThreshold(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
authorizer
|
||||
);
|
||||
if (revokeThreshold >= 1) {
|
||||
return false;
|
||||
} else if (setThreshold < 2) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Sets the DKIM public key hash for a given domain with authorization.
|
||||
* @dev This function allows an authorized user or a contract to set a DKIM public key hash. It uses EIP-1271 or ECDSA for signature verification.
|
||||
* @param domainName The domain name for which the DKIM public key hash is being set.
|
||||
* @param publicKeyHash The hash of the DKIM public key to be set.
|
||||
* @param authorizer The address of the authorizer who can set the DKIM public key hash.
|
||||
* @param signature The signature proving the authorization to set the DKIM public key hash.
|
||||
* @custom:require The domain name, public key hash, and authorizer address must not be zero.
|
||||
* @custom:require The public key hash must not be revoked.
|
||||
* @custom:require The signature must be valid according to EIP-1271 if the authorizer is a contract, or ECDSA if the authorizer is an EOA.
|
||||
* @custom:event DKIMPublicKeyHashRegistered Emitted when a DKIM public key hash is successfully set.
|
||||
*/
|
||||
function setDKIMPublicKeyHash(
|
||||
string memory domainName,
|
||||
bytes32 publicKeyHash,
|
||||
address authorizer,
|
||||
bytes memory signature
|
||||
) public {
|
||||
require(bytes(domainName).length > 0, "domain name cannot be zero");
|
||||
require(publicKeyHash != bytes32(0), "public key hash cannot be zero");
|
||||
require(authorizer != address(0), "authorizer address cannot be zero");
|
||||
require(
|
||||
revokedDKIMPublicKeyHashes[publicKeyHash][authorizer] == false,
|
||||
"public key hash is already revoked"
|
||||
);
|
||||
if (msg.sender != authorizer) {
|
||||
string memory signedMsg = computeSignedMsg(
|
||||
SET_PREFIX,
|
||||
domainName,
|
||||
publicKeyHash
|
||||
);
|
||||
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
|
||||
bytes(signedMsg)
|
||||
);
|
||||
if (authorizer.code.length > 0) {
|
||||
require(
|
||||
IERC1271(authorizer).isValidSignature(digest, signature) ==
|
||||
0x1626ba7e,
|
||||
"invalid eip1271 signature"
|
||||
);
|
||||
} else {
|
||||
address recoveredSigner = digest.recover(signature);
|
||||
require(
|
||||
recoveredSigner == authorizer,
|
||||
"invalid ecdsa signature"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
dkimPublicKeyHashes[domainName][publicKeyHash][authorizer] = true;
|
||||
|
||||
emit DKIMPublicKeyHashRegistered(domainName, publicKeyHash, authorizer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the DKIM public key hashes in batch.
|
||||
* @param domainNames An array of the domain name for which the DKIM public key hash is being set.
|
||||
* @param publicKeyHashes An array of the hash of the DKIM public key to be set.
|
||||
* @param authorizers An array of the address of the authorizer who can set the DKIM public key hash.
|
||||
* @param signatures An array of the signature proving the authorization to set the DKIM public key hash.
|
||||
* @custom:require The domain name, public key hash, and authorizer address must not be zero.
|
||||
* @custom:require The public key hash must not be revoked.
|
||||
* @custom:require The signature must be valid according to EIP-1271 if the authorizer is a contract, or ECDSA if the authorizer is an EOA.
|
||||
* @custom:event DKIMPublicKeyHashRegistered Emitted when a DKIM public key hash is successfully set.
|
||||
*/
|
||||
function setDKIMPublicKeyHashes(
|
||||
string[] memory domainNames,
|
||||
bytes32[] memory publicKeyHashes,
|
||||
address[] memory authorizers,
|
||||
bytes[] memory signatures
|
||||
) public {
|
||||
require(
|
||||
domainNames.length == publicKeyHashes.length,
|
||||
"invalid publicKeyHashes length"
|
||||
);
|
||||
require(
|
||||
domainNames.length == authorizers.length,
|
||||
"invalid authorizers length"
|
||||
);
|
||||
require(
|
||||
domainNames.length == signatures.length,
|
||||
"invalid signatures length"
|
||||
);
|
||||
for (uint256 i = 0; i < domainNames.length; i++) {
|
||||
setDKIMPublicKeyHash(
|
||||
domainNames[i],
|
||||
publicKeyHashes[i],
|
||||
authorizers[i],
|
||||
signatures[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Revokes a DKIM public key hash.
|
||||
* @dev This function allows the owner to revoke a DKIM public key hash for all users, or an individual user to revoke it for themselves.
|
||||
* @param domainName The domain name associated with the DKIM public key hash.
|
||||
* @param publicKeyHash The hash of the DKIM public key to be revoked.
|
||||
* @param authorizer The address of the authorizer who can revoke the DKIM public key hash.
|
||||
* @param signature The signature proving the authorization to revoke the DKIM public key hash.
|
||||
* @custom:require The domain name, public key hash, and authorizer address must not be zero.
|
||||
* @custom:require The public key hash must not already be revoked.
|
||||
* @custom:require The signature must be valid according to EIP-1271 if the authorizer is a contract, or ECDSA if the authorizer is an EOA.
|
||||
* @custom:event DKIMPublicKeyHashRevoked Emitted when a DKIM public key hash is successfully revoked.
|
||||
*/
|
||||
function revokeDKIMPublicKeyHash(
|
||||
string memory domainName,
|
||||
bytes32 publicKeyHash,
|
||||
address authorizer,
|
||||
bytes memory signature
|
||||
) public {
|
||||
require(bytes(domainName).length > 0, "domain name cannot be zero");
|
||||
require(publicKeyHash != bytes32(0), "public key hash cannot be zero");
|
||||
require(authorizer != address(0), "authorizer address cannot be zero");
|
||||
require(
|
||||
revokedDKIMPublicKeyHashes[publicKeyHash][authorizer] == false,
|
||||
"public key hash is already revoked"
|
||||
);
|
||||
if (msg.sender != authorizer) {
|
||||
string memory signedMsg = computeSignedMsg(
|
||||
REVOKE_PREFIX,
|
||||
domainName,
|
||||
publicKeyHash
|
||||
);
|
||||
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
|
||||
bytes(signedMsg)
|
||||
);
|
||||
if (authorizer.code.length > 0) {
|
||||
require(
|
||||
IERC1271(authorizer).isValidSignature(digest, signature) ==
|
||||
0x1626ba7e,
|
||||
"invalid eip1271 signature"
|
||||
);
|
||||
} else {
|
||||
address recoveredSigner = digest.recover(signature);
|
||||
require(
|
||||
recoveredSigner == authorizer,
|
||||
"invalid ecdsa signature"
|
||||
);
|
||||
}
|
||||
}
|
||||
revokedDKIMPublicKeyHashes[publicKeyHash][authorizer] = true;
|
||||
|
||||
emit DKIMPublicKeyHashRevoked(publicKeyHash, authorizer);
|
||||
}
|
||||
|
||||
function reactivateDKIMPublicKeyHash(
|
||||
string memory domainName,
|
||||
bytes32 publicKeyHash,
|
||||
address authorizer,
|
||||
bytes memory signature
|
||||
) public {
|
||||
require(bytes(domainName).length > 0, "domain name cannot be zero");
|
||||
require(publicKeyHash != bytes32(0), "public key hash cannot be zero");
|
||||
require(authorizer != address(0), "authorizer address cannot be zero");
|
||||
require(
|
||||
reactivatedDKIMPublicKeyHashes[publicKeyHash][authorizer] == false,
|
||||
"public key hash is already reactivated"
|
||||
);
|
||||
require(
|
||||
authorizer != mainAuthorizer,
|
||||
"mainAuthorizer cannot reactivate the public key hash"
|
||||
);
|
||||
require(
|
||||
_computeRevokeThreshold(publicKeyHash, authorizer) == 1,
|
||||
"revoke threshold must be one"
|
||||
);
|
||||
require(
|
||||
_computeSetThreshold(domainName, publicKeyHash, authorizer) >= 2,
|
||||
"set threshold must be larger than two"
|
||||
);
|
||||
if (msg.sender != authorizer) {
|
||||
string memory signedMsg = computeSignedMsg(
|
||||
REACTIVATE_PREFIX,
|
||||
domainName,
|
||||
publicKeyHash
|
||||
);
|
||||
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
|
||||
bytes(signedMsg)
|
||||
);
|
||||
if (authorizer.code.length > 0) {
|
||||
require(
|
||||
IERC1271(authorizer).isValidSignature(digest, signature) ==
|
||||
0x1626ba7e,
|
||||
"invalid eip1271 signature"
|
||||
);
|
||||
} else {
|
||||
address recoveredSigner = digest.recover(signature);
|
||||
require(
|
||||
recoveredSigner == authorizer,
|
||||
"invalid ecdsa signature"
|
||||
);
|
||||
}
|
||||
}
|
||||
reactivatedDKIMPublicKeyHashes[publicKeyHash][authorizer] = true;
|
||||
|
||||
emit DKIMPublicKeyHashReactivated(publicKeyHash, authorizer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Computes a signed message string for setting or revoking a DKIM public key hash.
|
||||
* @param prefix The operation prefix (SET: or REVOKE:).
|
||||
* @param domainName The domain name related to the operation.
|
||||
* @param publicKeyHash The DKIM public key hash involved in the operation.
|
||||
* @return string The computed signed message.
|
||||
* @dev This function is used internally to generate the message that needs to be signed for setting or revoking a public key hash.
|
||||
*/
|
||||
function computeSignedMsg(
|
||||
string memory prefix,
|
||||
string memory domainName,
|
||||
bytes32 publicKeyHash
|
||||
) public pure returns (string memory) {
|
||||
return
|
||||
string.concat(
|
||||
prefix,
|
||||
";domain=",
|
||||
domainName,
|
||||
";public_key_hash=",
|
||||
uint256(publicKeyHash).toHexString(),
|
||||
";"
|
||||
);
|
||||
}
|
||||
|
||||
function _computeSetThreshold(
|
||||
string memory domainName,
|
||||
bytes32 publicKeyHash,
|
||||
address authorizer
|
||||
) private view returns (uint256) {
|
||||
uint256 threshold = 0;
|
||||
if (
|
||||
dkimPublicKeyHashes[domainName][publicKeyHash][mainAuthorizer] ==
|
||||
true
|
||||
) {
|
||||
threshold += 1;
|
||||
}
|
||||
if (
|
||||
dkimPublicKeyHashes[domainName][publicKeyHash][authorizer] == true
|
||||
) {
|
||||
threshold += 2;
|
||||
}
|
||||
return threshold;
|
||||
}
|
||||
|
||||
function _computeRevokeThreshold(
|
||||
bytes32 publicKeyHash,
|
||||
address authorizer
|
||||
) private view returns (uint256) {
|
||||
uint256 threshold = 0;
|
||||
if (revokedDKIMPublicKeyHashes[publicKeyHash][mainAuthorizer] == true) {
|
||||
threshold += 1;
|
||||
}
|
||||
if (revokedDKIMPublicKeyHashes[publicKeyHash][authorizer] == true) {
|
||||
threshold += 2;
|
||||
}
|
||||
if (
|
||||
threshold == 1 &&
|
||||
reactivatedDKIMPublicKeyHashes[publicKeyHash][authorizer] == true
|
||||
) {
|
||||
threshold -= 1;
|
||||
}
|
||||
return threshold;
|
||||
}
|
||||
|
||||
function _stringEq(
|
||||
string memory a,
|
||||
string memory b
|
||||
) internal pure returns (bool) {
|
||||
return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
|
||||
}
|
||||
}
|
||||
@@ -3,4 +3,4 @@ src = './'
|
||||
out = 'out'
|
||||
allow_paths = ['../../node_modules']
|
||||
libs = ['../../node_modules']
|
||||
solc_version = '0.8.21'
|
||||
solc_version = '0.8.23'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zk-email/contracts",
|
||||
"version": "6.1.1",
|
||||
"version": "6.1.2",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "forge build",
|
||||
@@ -12,6 +12,7 @@
|
||||
},
|
||||
"files": [
|
||||
"DKIMRegistry.sol",
|
||||
"UserOverrideableDKIMRegistry.sol",
|
||||
"/utils",
|
||||
"/interfaces"
|
||||
],
|
||||
|
||||
745
packages/contracts/test/UserOverrideableDKIMRegistry.t.sol
Normal file
745
packages/contracts/test/UserOverrideableDKIMRegistry.t.sol
Normal file
@@ -0,0 +1,745 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.12;
|
||||
|
||||
import "forge-std/src/Test.sol";
|
||||
import "forge-std/src/console.sol";
|
||||
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
||||
import "../UserOverrideableDKIMRegistry.sol";
|
||||
import "@openzeppelin/contracts/utils/Strings.sol";
|
||||
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
|
||||
import "./helpers/ExampleERC1271.sol";
|
||||
import "./helpers/ExampleOwnable.sol";
|
||||
|
||||
contract UserOverrideableDKIMRegistryTest is Test {
|
||||
UserOverrideableDKIMRegistry registry;
|
||||
using console for *;
|
||||
using ECDSA for *;
|
||||
using Strings for *;
|
||||
|
||||
string public domainName = "example.com";
|
||||
bytes32 public publicKeyHash = bytes32(uint256(1));
|
||||
bytes32 public publicKeyHash2 = bytes32(uint256(2));
|
||||
|
||||
address deployer;
|
||||
address mainAuthorizer;
|
||||
address user1;
|
||||
address user2;
|
||||
|
||||
UserOverrideableDKIMRegistry registryWithContract;
|
||||
ExampleERC1271 mainAuthorizerContract;
|
||||
ExampleOwnable exampleOwnable;
|
||||
|
||||
function setUp() public {
|
||||
deployer = vm.addr(1);
|
||||
mainAuthorizer = vm.addr(9);
|
||||
user1 = vm.addr(2);
|
||||
user2 = vm.addr(3);
|
||||
registry = new UserOverrideableDKIMRegistry(deployer, mainAuthorizer);
|
||||
exampleOwnable = new ExampleOwnable(mainAuthorizer);
|
||||
mainAuthorizerContract = new ExampleERC1271(mainAuthorizer);
|
||||
registryWithContract = new UserOverrideableDKIMRegistry(
|
||||
deployer,
|
||||
address(mainAuthorizerContract)
|
||||
);
|
||||
}
|
||||
|
||||
function testSetDKIMPublicKeyHashByMainAuthorizer() public {
|
||||
vm.startPrank(mainAuthorizer);
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRegistered(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
mainAuthorizer
|
||||
);
|
||||
registry.setDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
mainAuthorizer,
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
|
||||
// Call by a Ownable contract
|
||||
vm.startPrank(address(exampleOwnable));
|
||||
// setThreshold = 2
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(domainName, publicKeyHash),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testSetDKIMPublicKeyHashByMainAuthorizerContract() public {
|
||||
vm.startPrank(address(mainAuthorizerContract));
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRegistered(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract)
|
||||
);
|
||||
registry.setDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract),
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract)
|
||||
),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
}
|
||||
|
||||
function testSetDKIMPublicKeyHashByUser1() public {
|
||||
vm.startPrank(user1);
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRegistered(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
user1
|
||||
);
|
||||
registry.setDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
user1,
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
|
||||
// setThreshold = 2
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(domainName, publicKeyHash, user1),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
}
|
||||
|
||||
function testIsDKIMPublicKeyHashValidByUser2() public {
|
||||
testSetDKIMPublicKeyHashByUser1();
|
||||
|
||||
vm.startPrank(user1);
|
||||
|
||||
// setThreshold = 2
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(domainName, publicKeyHash, user1),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testFailIsDKIMPublicKeyHashValidByUser2() public {
|
||||
testSetDKIMPublicKeyHashByUser1();
|
||||
|
||||
vm.startPrank(user2);
|
||||
|
||||
// setThreshold = 0
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(domainName, publicKeyHash),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testExpectRevertDomainNameCannotBeZeroSetDKIMPublicKeyHashByUser1()
|
||||
public
|
||||
{
|
||||
vm.startPrank(user1);
|
||||
|
||||
vm.expectRevert("domain name cannot be zero");
|
||||
registry.setDKIMPublicKeyHash("", publicKeyHash, user1, new bytes(0));
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testExpectRevertPublicKeyHashCannotBeZeroSetDKIMPublicKeyHashByUser1()
|
||||
public
|
||||
{
|
||||
vm.startPrank(user1);
|
||||
|
||||
vm.expectRevert("public key hash cannot be zero");
|
||||
registry.setDKIMPublicKeyHash(
|
||||
domainName,
|
||||
bytes32(uint256(0)),
|
||||
user1,
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testExpectRevertAuthorizerAddressCannotBeZeroSetDKIMPublicKeyHashByUser1()
|
||||
public
|
||||
{
|
||||
vm.startPrank(user1);
|
||||
|
||||
vm.expectRevert("authorizer address cannot be zero");
|
||||
registry.setDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(0),
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testExpectRevertPublicKeyHashIsAlreadyRevokedSetDKIMPublicKeyHashByUser1()
|
||||
public
|
||||
{
|
||||
testRevokeDKIMPublicKeyHashByUser1();
|
||||
vm.startPrank(user1);
|
||||
|
||||
vm.expectRevert("public key hash is already revoked");
|
||||
registry.setDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
user1,
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testSetDKIMPublicKeyHashOfMainAuthorizerByUser1() public {
|
||||
vm.startPrank(user1);
|
||||
|
||||
string memory signedMsg = registry.computeSignedMsg(
|
||||
registry.SET_PREFIX(),
|
||||
domainName,
|
||||
publicKeyHash
|
||||
);
|
||||
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
|
||||
bytes(signedMsg)
|
||||
);
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(9, digest);
|
||||
bytes memory signature = abi.encodePacked(r, s, v);
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRegistered(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
mainAuthorizer
|
||||
);
|
||||
registry.setDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
mainAuthorizer,
|
||||
signature
|
||||
);
|
||||
// setThreshold = 3
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
mainAuthorizer
|
||||
),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testFailSetDKIMPublicKeyHashOfMainAuthorizerByUser1() public {
|
||||
vm.startPrank(user1);
|
||||
|
||||
string memory signedMsg = registry.computeSignedMsg(
|
||||
registry.SET_PREFIX(),
|
||||
domainName,
|
||||
publicKeyHash
|
||||
);
|
||||
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
|
||||
bytes(signedMsg)
|
||||
);
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(9, digest);
|
||||
bytes memory signature = abi.encodePacked(r, s, v);
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRegistered(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
mainAuthorizer
|
||||
);
|
||||
registry.setDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
mainAuthorizer,
|
||||
signature
|
||||
);
|
||||
// setThreshold = 1
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(domainName, publicKeyHash),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testSetDKIMPublicKeyHashOfMainAuthorizerAsContractByUser1()
|
||||
public
|
||||
{
|
||||
vm.startPrank(user1);
|
||||
|
||||
string memory signedMsg = registryWithContract.computeSignedMsg(
|
||||
registryWithContract.SET_PREFIX(),
|
||||
domainName,
|
||||
publicKeyHash
|
||||
);
|
||||
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
|
||||
bytes(signedMsg)
|
||||
);
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(9, digest);
|
||||
bytes memory signature = abi.encodePacked(r, s, v);
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRegistered(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract)
|
||||
);
|
||||
registryWithContract.setDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract),
|
||||
signature
|
||||
);
|
||||
// setThreshold = 3
|
||||
require(
|
||||
registryWithContract.isDKIMPublicKeyHashValid(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract)
|
||||
),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testFailSetDKIMPublicKeyHashOfMainAuthorizerAsContractByUser1()
|
||||
public
|
||||
{
|
||||
vm.startPrank(user1);
|
||||
|
||||
string memory signedMsg = registryWithContract.computeSignedMsg(
|
||||
registryWithContract.SET_PREFIX(),
|
||||
domainName,
|
||||
publicKeyHash
|
||||
);
|
||||
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
|
||||
bytes(signedMsg)
|
||||
);
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(9, digest);
|
||||
bytes memory signature = abi.encodePacked(r, s, v);
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRegistered(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract)
|
||||
);
|
||||
registryWithContract.setDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract),
|
||||
signature
|
||||
);
|
||||
// setThreshold = 1
|
||||
require(
|
||||
registryWithContract.isDKIMPublicKeyHashValid(
|
||||
domainName,
|
||||
publicKeyHash
|
||||
),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testRevokeDKIMPublicKeyHashByMainAuthorizer() public {
|
||||
testSetDKIMPublicKeyHashByMainAuthorizer();
|
||||
|
||||
vm.startPrank(mainAuthorizer);
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRevoked(
|
||||
publicKeyHash,
|
||||
mainAuthorizer
|
||||
);
|
||||
registry.revokeDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
mainAuthorizer,
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testRevokeDKIMPublicKeyHashByUser1() public {
|
||||
testSetDKIMPublicKeyHashByUser1();
|
||||
|
||||
vm.startPrank(user1);
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRevoked(
|
||||
publicKeyHash,
|
||||
user1
|
||||
);
|
||||
registry.revokeDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
user1,
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testExpectRevertDomainNameCannotBeZeroRevokeDKIMPublicKeyHashByUser1()
|
||||
public
|
||||
{
|
||||
testSetDKIMPublicKeyHashByUser1();
|
||||
|
||||
vm.startPrank(user1);
|
||||
vm.expectRevert("domain name cannot be zero");
|
||||
registry.revokeDKIMPublicKeyHash(
|
||||
"",
|
||||
publicKeyHash,
|
||||
user1,
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testExpectRevertPublicKeyHashCannotBeZeroRevokeDKIMPublicKeyHashByUser1()
|
||||
public
|
||||
{
|
||||
testSetDKIMPublicKeyHashByUser1();
|
||||
|
||||
vm.startPrank(user1);
|
||||
vm.expectRevert("public key hash cannot be zero");
|
||||
registry.revokeDKIMPublicKeyHash(
|
||||
domainName,
|
||||
bytes32(uint256(0)),
|
||||
user1,
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testExpectRevertAuthorizerAddressCannotBeZeroRevokeDKIMPublicKeyHashByUser1()
|
||||
public
|
||||
{
|
||||
testSetDKIMPublicKeyHashByUser1();
|
||||
|
||||
vm.startPrank(user1);
|
||||
vm.expectRevert("authorizer address cannot be zero");
|
||||
registry.revokeDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(0),
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testExpectRevertPublicKeyHashIsAlreadyRevokedRevokeDKIMPublicKeyHashByUser1()
|
||||
public
|
||||
{
|
||||
testRevokeDKIMPublicKeyHashByUser1();
|
||||
|
||||
vm.startPrank(user1);
|
||||
vm.expectRevert("public key hash is already revoked");
|
||||
registry.revokeDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
user1,
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testRevokeDKIMPublicKeyHashOfMainAuthorizerByUser1() public {
|
||||
testSetDKIMPublicKeyHashByUser1();
|
||||
|
||||
vm.startPrank(user1);
|
||||
|
||||
string memory signedMsg = registry.computeSignedMsg(
|
||||
registry.REVOKE_PREFIX(),
|
||||
domainName,
|
||||
publicKeyHash
|
||||
);
|
||||
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
|
||||
bytes(signedMsg)
|
||||
);
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(9, digest);
|
||||
bytes memory signature = abi.encodePacked(r, s, v);
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRevoked(
|
||||
publicKeyHash,
|
||||
mainAuthorizer
|
||||
);
|
||||
registry.revokeDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
mainAuthorizer,
|
||||
signature
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testFailIsDKIMPublicKeyHashValidByUser1AfterRevokedByMainAuthorizer()
|
||||
public
|
||||
{
|
||||
testRevokeDKIMPublicKeyHashOfMainAuthorizerByUser1();
|
||||
|
||||
vm.startPrank(user1);
|
||||
// removeThreshold = 1
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(domainName, publicKeyHash),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testRevokeDKIMPublicKeyHashOfMainAuthorizerAsContractByUser1()
|
||||
public
|
||||
{
|
||||
testSetDKIMPublicKeyHashOfMainAuthorizerAsContractByUser1();
|
||||
|
||||
vm.startPrank(user1);
|
||||
|
||||
string memory signedMsg = registryWithContract.computeSignedMsg(
|
||||
registryWithContract.REVOKE_PREFIX(),
|
||||
domainName,
|
||||
publicKeyHash
|
||||
);
|
||||
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
|
||||
bytes(signedMsg)
|
||||
);
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(9, digest);
|
||||
bytes memory signature = abi.encodePacked(r, s, v);
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRevoked(
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract)
|
||||
);
|
||||
registryWithContract.revokeDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract),
|
||||
signature
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testSetDKIMPublicKeyHashesByUser1() public {
|
||||
vm.startPrank(user1);
|
||||
string[] memory domainNames = new string[](2);
|
||||
domainNames[0] = domainName;
|
||||
domainNames[1] = domainName;
|
||||
bytes32[] memory publicKeyHashes = new bytes32[](2);
|
||||
publicKeyHashes[0] = publicKeyHash;
|
||||
publicKeyHashes[1] = publicKeyHash2;
|
||||
address[] memory authorizers = new address[](2);
|
||||
authorizers[0] = user1;
|
||||
authorizers[1] = user1;
|
||||
bytes[] memory signatures = new bytes[](2);
|
||||
signatures[0] = new bytes(0);
|
||||
signatures[1] = new bytes(0);
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRegistered(
|
||||
domainName,
|
||||
publicKeyHashes[0],
|
||||
authorizers[0]
|
||||
);
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashRegistered(
|
||||
domainName,
|
||||
publicKeyHashes[1],
|
||||
authorizers[1]
|
||||
);
|
||||
registry.setDKIMPublicKeyHashes(
|
||||
domainNames,
|
||||
publicKeyHashes,
|
||||
authorizers,
|
||||
signatures
|
||||
);
|
||||
|
||||
// setThreshold = 2
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(
|
||||
domainName,
|
||||
publicKeyHashes[0],
|
||||
user1
|
||||
),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
// setThreshold = 2
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(
|
||||
domainName,
|
||||
publicKeyHashes[1],
|
||||
user1
|
||||
),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testFailisDKIMPublicKeyHashValidByUser2() public {
|
||||
testSetDKIMPublicKeyHashesByUser1();
|
||||
|
||||
vm.startPrank(user2);
|
||||
// setThreshold = 0
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(domainName, publicKeyHash),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testcomputeSignedMsg() public {
|
||||
string memory signedMsg = registry.computeSignedMsg(
|
||||
registry.SET_PREFIX(),
|
||||
domainName,
|
||||
publicKeyHash
|
||||
);
|
||||
require(
|
||||
Strings.equal(
|
||||
signedMsg,
|
||||
"SET:;domain=example.com;public_key_hash=0x01;"
|
||||
),
|
||||
"Invalid signed message"
|
||||
);
|
||||
console.log(signedMsg);
|
||||
}
|
||||
|
||||
function testReactivateDKIMPublicKeyHashByUser1() public {
|
||||
testSetDKIMPublicKeyHashByUser1();
|
||||
testRevokeDKIMPublicKeyHashByMainAuthorizer();
|
||||
|
||||
require(
|
||||
!registry.isDKIMPublicKeyHashValid(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
user1
|
||||
),
|
||||
"public key hash is not revoked"
|
||||
);
|
||||
|
||||
vm.startPrank(user1);
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashReactivated(
|
||||
publicKeyHash,
|
||||
user1
|
||||
);
|
||||
registry.reactivateDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
user1,
|
||||
new bytes(0)
|
||||
);
|
||||
vm.stopPrank();
|
||||
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(domainName, publicKeyHash, user1),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
}
|
||||
|
||||
function testReactivateDKIMPublicKeyHashByUser2WithUser1Signature() public {
|
||||
testSetDKIMPublicKeyHashByUser1();
|
||||
testRevokeDKIMPublicKeyHashByMainAuthorizer();
|
||||
|
||||
require(
|
||||
!registry.isDKIMPublicKeyHashValid(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
user1
|
||||
),
|
||||
"public key hash is not revoked"
|
||||
);
|
||||
|
||||
vm.startPrank(user2);
|
||||
|
||||
string memory signedMsg = registryWithContract.computeSignedMsg(
|
||||
registryWithContract.REACTIVATE_PREFIX(),
|
||||
domainName,
|
||||
publicKeyHash
|
||||
);
|
||||
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
|
||||
bytes(signedMsg)
|
||||
);
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(2, digest);
|
||||
bytes memory signature = abi.encodePacked(r, s, v);
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashReactivated(
|
||||
publicKeyHash,
|
||||
user1
|
||||
);
|
||||
registry.reactivateDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
user1,
|
||||
signature
|
||||
);
|
||||
vm.stopPrank();
|
||||
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(domainName, publicKeyHash, user1),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
}
|
||||
|
||||
function testReactivateDKIMPublicKeyHashByUser1WithMainAuthorizerSignature()
|
||||
public
|
||||
{
|
||||
testSetDKIMPublicKeyHashByMainAuthorizerContract();
|
||||
testRevokeDKIMPublicKeyHashByMainAuthorizer();
|
||||
|
||||
require(
|
||||
!registry.isDKIMPublicKeyHashValid(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract)
|
||||
),
|
||||
"public key hash is not revoked"
|
||||
);
|
||||
|
||||
vm.startPrank(user1);
|
||||
|
||||
string memory signedMsg = registryWithContract.computeSignedMsg(
|
||||
registryWithContract.REACTIVATE_PREFIX(),
|
||||
domainName,
|
||||
publicKeyHash
|
||||
);
|
||||
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
|
||||
bytes(signedMsg)
|
||||
);
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(9, digest);
|
||||
bytes memory signature = abi.encodePacked(r, s, v);
|
||||
|
||||
vm.expectEmit();
|
||||
emit UserOverrideableDKIMRegistry.DKIMPublicKeyHashReactivated(
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract)
|
||||
);
|
||||
registry.reactivateDKIMPublicKeyHash(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract),
|
||||
signature
|
||||
);
|
||||
vm.stopPrank();
|
||||
|
||||
require(
|
||||
registry.isDKIMPublicKeyHashValid(
|
||||
domainName,
|
||||
publicKeyHash,
|
||||
address(mainAuthorizerContract)
|
||||
),
|
||||
"Invalid public key hash"
|
||||
);
|
||||
}
|
||||
}
|
||||
28
packages/contracts/test/helpers/ExampleERC1271.sol
Normal file
28
packages/contracts/test/helpers/ExampleERC1271.sol
Normal file
@@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
||||
|
||||
// https://eips.ethereum.org/EIPS/eip-1271
|
||||
contract ExampleERC1271 is IERC1271, Ownable {
|
||||
using ECDSA for *;
|
||||
|
||||
constructor(address _owner) Ownable(_owner) {}
|
||||
|
||||
/**
|
||||
* @notice Verifies that the signer is the owner of the signing contract.
|
||||
*/
|
||||
function isValidSignature(
|
||||
bytes32 _hash,
|
||||
bytes calldata _signature
|
||||
) external view override returns (bytes4) {
|
||||
// Validate signatures
|
||||
if (_hash.recover(_signature) == owner()) {
|
||||
return 0x1626ba7e;
|
||||
} else {
|
||||
return 0xffffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
packages/contracts/test/helpers/ExampleOwnable.sol
Normal file
8
packages/contracts/test/helpers/ExampleOwnable.sol
Normal file
@@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
|
||||
contract ExampleOwnable is Ownable {
|
||||
constructor(address _owner) Ownable(_owner) {}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zk-email/helpers",
|
||||
"version": "6.1.1",
|
||||
"version": "6.1.2",
|
||||
"license": "MIT",
|
||||
"main": "dist",
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user