Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: extract shared EIP712 base contract #370

Merged
merged 1 commit into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
BundleRegistryGasUsageTest:testGasRegisterWithSig() (gas: 834117)
BundleRegistryGasUsageTest:testGasTrustedBatchRegister() (gas: 7091701)
BundleRegistryGasUsageTest:testGasTrustedRegister() (gas: 918443)
IdRegistryGasUsageTest:testGasRegister() (gas: 736116)
IdRegistryGasUsageTest:testGasRegisterForAndRecover() (gas: 1743798)
IdRegistryGasUsageTest:testGasRegisterFromTrustedCaller() (gas: 809179)
BundleRegistryGasUsageTest:testGasRegisterWithSig() (gas: 833506)
BundleRegistryGasUsageTest:testGasTrustedBatchRegister() (gas: 7078545)
BundleRegistryGasUsageTest:testGasTrustedRegister() (gas: 917167)
IdRegistryGasUsageTest:testGasRegister() (gas: 735456)
IdRegistryGasUsageTest:testGasRegisterForAndRecover() (gas: 1741402)
IdRegistryGasUsageTest:testGasRegisterFromTrustedCaller() (gas: 807023)
StorageRegistryGasUsageTest:testGasBatchCredit() (gas: 173053)
StorageRegistryGasUsageTest:testGasBatchRent() (gas: 270570)
StorageRegistryGasUsageTest:testGasContinuousCredit() (gas: 166530)
Expand Down
15 changes: 4 additions & 11 deletions src/FnameResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ pragma solidity 0.8.21;

import {Ownable2Step} from "openzeppelin/contracts/access/Ownable2Step.sol";
import {ECDSA} from "openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {EIP712} from "openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {ERC165} from "openzeppelin/contracts/utils/introspection/ERC165.sol";

import {EIP712} from "./lib/EIP712.sol";

interface IAddressQuery {
function addr(bytes32 node) external view returns (address);
}
Expand Down Expand Up @@ -78,7 +79,7 @@ contract FnameResolver is IExtendedResolver, EIP712, ERC165, Ownable2Step {
/**
* @dev EIP-712 typehash of the UsernameProof struct.
*/
bytes32 internal constant _USERNAME_PROOF_TYPEHASH =
bytes32 public constant USERNAME_PROOF_TYPEHASH =
keccak256("UserNameProof(string name,uint256 timestamp,address owner)");

/*//////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -162,7 +163,7 @@ contract FnameResolver is IExtendedResolver, EIP712, ERC165, Ownable2Step {
abi.decode(response, (string, uint256, address, bytes));

bytes32 proofHash =
keccak256(abi.encode(_USERNAME_PROOF_TYPEHASH, keccak256(bytes(fname)), timestamp, fnameOwner));
keccak256(abi.encode(USERNAME_PROOF_TYPEHASH, keccak256(bytes(fname)), timestamp, fnameOwner));
bytes32 eip712hash = _hashTypedDataV4(proofHash);
address signer = ECDSA.recover(eip712hash, signature);

Expand All @@ -171,14 +172,6 @@ contract FnameResolver is IExtendedResolver, EIP712, ERC165, Ownable2Step {
return abi.encode(fnameOwner);
}

/*//////////////////////////////////////////////////////////////
EIP-712 HELPERS
//////////////////////////////////////////////////////////////*/

function hashTypedDataV4(bytes32 structHash) external view returns (bytes32) {
return _hashTypedDataV4(structHash);
}

/*//////////////////////////////////////////////////////////////
PERMISSIONED ACTIONS
//////////////////////////////////////////////////////////////*/
Expand Down
14 changes: 7 additions & 7 deletions src/IdRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
pragma solidity 0.8.21;

import {SignatureChecker} from "openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import {EIP712} from "openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {Nonces} from "openzeppelin-latest/contracts/utils/Nonces.sol";
import {Pausable} from "openzeppelin/contracts/security/Pausable.sol";

import {EIP712} from "./lib/EIP712.sol";
import {Signatures} from "./lib/Signatures.sol";
import {TrustedCaller} from "./lib/TrustedCaller.sol";

Expand Down Expand Up @@ -89,13 +89,13 @@ contract IdRegistry is TrustedCaller, Signatures, Pausable, EIP712, Nonces {
CONSTANTS
//////////////////////////////////////////////////////////////*/

bytes32 internal constant _REGISTER_TYPEHASH =
bytes32 public constant REGISTER_TYPEHASH =
keccak256("Register(address to,address recovery,uint256 nonce,uint256 deadline)");

bytes32 internal constant _TRANSFER_TYPEHASH =
bytes32 public constant TRANSFER_TYPEHASH =
keccak256("Transfer(uint256 fid,address to,uint256 nonce,uint256 deadline)");

bytes32 internal constant _CHANGE_RECOVERY_ADDRESS_TYPEHASH =
bytes32 public constant CHANGE_RECOVERY_ADDRESS_TYPEHASH =
keccak256("ChangeRecoveryAddress(uint256 fid,address recovery,uint256 nonce,uint256 deadline)");

/*//////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -446,7 +446,7 @@ contract IdRegistry is TrustedCaller, Signatures, Pausable, EIP712, Nonces {

function _verifyRegisterSig(address to, address recovery, uint256 deadline, bytes memory sig) internal {
_verifySig(
_hashTypedDataV4(keccak256(abi.encode(_REGISTER_TYPEHASH, to, recovery, _useNonce(to), deadline))),
_hashTypedDataV4(keccak256(abi.encode(REGISTER_TYPEHASH, to, recovery, _useNonce(to), deadline))),
to,
deadline,
sig
Expand All @@ -455,7 +455,7 @@ contract IdRegistry is TrustedCaller, Signatures, Pausable, EIP712, Nonces {

function _verifyTransferSig(uint256 fid, address to, uint256 deadline, address signer, bytes memory sig) internal {
_verifySig(
_hashTypedDataV4(keccak256(abi.encode(_TRANSFER_TYPEHASH, fid, to, _useNonce(signer), deadline))),
_hashTypedDataV4(keccak256(abi.encode(TRANSFER_TYPEHASH, fid, to, _useNonce(signer), deadline))),
signer,
deadline,
sig
Expand All @@ -471,7 +471,7 @@ contract IdRegistry is TrustedCaller, Signatures, Pausable, EIP712, Nonces {
) internal {
_verifySig(
_hashTypedDataV4(
keccak256(abi.encode(_CHANGE_RECOVERY_ADDRESS_TYPEHASH, fid, recovery, _useNonce(signer), deadline))
keccak256(abi.encode(CHANGE_RECOVERY_ADDRESS_TYPEHASH, fid, recovery, _useNonce(signer), deadline))
),
signer,
deadline,
Expand Down
10 changes: 5 additions & 5 deletions src/KeyRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;

import {EIP712} from "openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {Nonces} from "openzeppelin-latest/contracts/utils/Nonces.sol";
import {Pausable} from "openzeppelin/contracts/security/Pausable.sol";

import {EIP712} from "./lib/EIP712.sol";
import {IdRegistryLike} from "./interfaces/IdRegistryLike.sol";
import {IMetadataValidator} from "./interfaces/IMetadataValidator.sol";
import {IdRegistry} from "./IdRegistry.sol";
Expand Down Expand Up @@ -190,11 +190,11 @@ contract KeyRegistry is TrustedCaller, Signatures, Pausable, EIP712, Nonces {
CONSTANTS
//////////////////////////////////////////////////////////////*/

bytes32 internal constant _ADD_TYPEHASH = keccak256(
bytes32 public constant ADD_TYPEHASH = keccak256(
"Add(address owner,uint32 keyType,bytes key,uint8 metadataType,bytes metadata,uint256 nonce,uint256 deadline)"
);

bytes32 internal constant _REMOVE_TYPEHASH =
bytes32 public constant REMOVE_TYPEHASH =
keccak256("Remove(address owner,bytes key,uint256 nonce,uint256 deadline)");

/**
Expand Down Expand Up @@ -569,7 +569,7 @@ contract KeyRegistry is TrustedCaller, Signatures, Pausable, EIP712, Nonces {
_hashTypedDataV4(
keccak256(
abi.encode(
_ADD_TYPEHASH,
ADD_TYPEHASH,
fidOwner,
keyType,
keccak256(key),
Expand All @@ -589,7 +589,7 @@ contract KeyRegistry is TrustedCaller, Signatures, Pausable, EIP712, Nonces {
function _verifyRemoveSig(address fidOwner, bytes memory key, uint256 deadline, bytes memory sig) internal {
_verifySig(
_hashTypedDataV4(
keccak256(abi.encode(_REMOVE_TYPEHASH, fidOwner, keccak256(key), _useNonce(fidOwner), deadline))
keccak256(abi.encode(REMOVE_TYPEHASH, fidOwner, keccak256(key), _useNonce(fidOwner), deadline))
),
fidOwner,
deadline,
Expand Down
32 changes: 32 additions & 0 deletions src/lib/EIP712.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;

import {EIP712 as EIP712Base} from "openzeppelin/contracts/utils/cryptography/EIP712.sol";

abstract contract EIP712 is EIP712Base {
constructor(string memory name, string memory version) EIP712Base(name, version) {}

/*//////////////////////////////////////////////////////////////
EIP-712 HELPERS
//////////////////////////////////////////////////////////////*/

/**
* @notice Helper view to read EIP-712 domain separator.
*
* @return bytes32 domain separator hash.
*/
function domainSeparatorV4() external view returns (bytes32) {
return _domainSeparatorV4();
}

/**
* @notice Helper view to hash EIP-712 typed data onchain.
*
* @param structHash EIP-712 typed data hash.
*
* @return bytes32 EIP-712 message digest.
*/
function hashTypedDataV4(bytes32 structHash) external view returns (bytes32) {
return _hashTypedDataV4(structHash);
}
}
17 changes: 10 additions & 7 deletions src/validators/SignedKeyRequestValidator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
pragma solidity 0.8.21;

import {Ownable2Step} from "openzeppelin/contracts/access/Ownable2Step.sol";
import {EIP712} from "openzeppelin/contracts/utils/cryptography/EIP712.sol";

import {EIP712} from "../lib/EIP712.sol";
import {IMetadataValidator} from "../interfaces/IMetadataValidator.sol";
import {IdRegistryLike} from "../interfaces/IdRegistryLike.sol";
import {IdRegistry} from "../IdRegistry.sol";
Expand Down Expand Up @@ -46,7 +46,7 @@ contract SignedKeyRequestValidator is IMetadataValidator, Ownable2Step, EIP712 {
CONSTANTS
//////////////////////////////////////////////////////////////*/

bytes32 internal constant _METADATA_TYPEHASH =
bytes32 public constant METADATA_TYPEHASH =
keccak256("SignedKeyRequest(uint256 requestFid,bytes key,uint256 deadline)");

/*//////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -104,7 +104,7 @@ contract SignedKeyRequestValidator is IMetadataValidator, Ownable2Step, EIP712 {
metadata.requestSigner,
metadata.requestFid,
_hashTypedDataV4(
keccak256(abi.encode(_METADATA_TYPEHASH, metadata.requestFid, keccak256(key), metadata.deadline))
keccak256(abi.encode(METADATA_TYPEHASH, metadata.requestFid, keccak256(key), metadata.deadline))
),
metadata.signature
);
Expand All @@ -114,10 +114,13 @@ contract SignedKeyRequestValidator is IMetadataValidator, Ownable2Step, EIP712 {
HELPERS
//////////////////////////////////////////////////////////////*/

function hashTypedDataV4(bytes32 structHash) external view returns (bytes32) {
return _hashTypedDataV4(structHash);
}

/**
* @notice ABI-encode a SignedKeyRequestMetadata struct.
*
* @param metadata The SignedKeyRequestMetadata struct to encode.
*
* @return bytes memory Bytes of ABI-encoded struct.
*/
function encodeMetadata(SignedKeyRequestMetadata calldata metadata) external pure returns (bytes memory) {
return abi.encode(metadata);
}
Expand Down
8 changes: 3 additions & 5 deletions test/Bundler/BundlerTestSuite.sol
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;

import {IdRegistryHarness} from "../Utils.sol";
import {TestSuiteSetup} from "../TestSuiteSetup.sol";
import {StorageRegistryTestSuite} from "../StorageRegistry/StorageRegistryTestSuite.sol";
import {IdRegistryTestSuite} from "../IdRegistry/IdRegistryTestSuite.sol";
import {KeyRegistryTestSuite} from "../KeyRegistry/KeyRegistryTestSuite.sol";

import {BundlerHarness} from "../Utils.sol";
import {Bundler} from "../../src/Bundler.sol";

/* solhint-disable state-visibility */

abstract contract BundlerTestSuite is StorageRegistryTestSuite, KeyRegistryTestSuite {
// Instance of the BundleRegistry contract wrapped in its test wrapper
BundlerHarness bundler;
Bundler bundler;

function setUp() public virtual override(StorageRegistryTestSuite, KeyRegistryTestSuite) {
super.setUp();

// Set up the BundleRegistry
bundler = new BundlerHarness(
bundler = new Bundler(
address(idRegistry),
address(storageRegistry),
address(keyRegistry),
Expand Down
33 changes: 5 additions & 28 deletions test/Deploy/DeployL1.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import "forge-std/console.sol";
/* solhint-disable state-visibility */

contract DeployL1Test is DeployL1, FnameResolverTestSuite {
FnameResolver internal fnameResolver;

address internal deployer = address(this);
address internal alpha = makeAddr("alpha");
address internal alice = makeAddr("alice");
Expand All @@ -30,43 +28,22 @@ contract DeployL1Test is DeployL1, FnameResolverTestSuite {

DeployL1.Contracts memory contracts = runDeploy(params, false);

fnameResolver = contracts.fnameResolver;
resolver = contracts.fnameResolver;
}

function test_deploymentParams() public {
// Check deployment parameters
assertEq(fnameResolver.url(), "https://fnames.farcaster.xyz/ccip/{sender}/{data}.json");
assertEq(fnameResolver.owner(), alpha);
assertEq(fnameResolver.signers(signer), true);
assertEq(resolver.url(), "https://fnames.farcaster.xyz/ccip/{sender}/{data}.json");
assertEq(resolver.owner(), alpha);
assertEq(resolver.signers(signer), true);
}

function test_e2e() public {
uint256 timestamp = block.timestamp - 60;
bytes memory signature = _signProof(signerPk, "alice.fcast.id", timestamp, alice);
bytes memory extraData = abi.encodeCall(IResolverService.resolve, (DNS_ENCODED_NAME, ADDR_QUERY_CALLDATA));
bytes memory response =
fnameResolver.resolveWithProof(abi.encode("alice.fcast.id", timestamp, alice, signature), extraData);
resolver.resolveWithProof(abi.encode("alice.fcast.id", timestamp, alice, signature), extraData);
assertEq(response, abi.encode(alice));
}

function _signProof(
uint256 pk,
string memory name,
uint256 timestamp,
address owner
) internal returns (bytes memory signature) {
bytes32 eip712hash = fnameResolver.hashTypedDataV4(
keccak256(
abi.encode(
keccak256("UserNameProof(string name,uint256 timestamp,address owner)"),
keccak256(bytes(name)),
timestamp,
owner
)
)
);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(pk, eip712hash);
signature = abi.encodePacked(r, s, v);
assertEq(signature.length, 65);
}
}
28 changes: 1 addition & 27 deletions test/FnameResolver/FnameResolver.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ contract FnameResolverTest is FnameResolverTestSuite {

function testProofTypehash() public {
assertEq(
resolver.usernameProofTypehash(), keccak256("UserNameProof(string name,uint256 timestamp,address owner)")
resolver.USERNAME_PROOF_TYPEHASH(), keccak256("UserNameProof(string name,uint256 timestamp,address owner)")
);
}

Expand Down Expand Up @@ -182,30 +182,4 @@ contract FnameResolverTest is FnameResolverTestSuite {
vm.assume(interfaceId != type(IExtendedResolver).interfaceId && interfaceId != type(IERC165).interfaceId);
assertEq(resolver.supportsInterface(interfaceId), false);
}

/*//////////////////////////////////////////////////////////////
HELPERS
//////////////////////////////////////////////////////////////*/

function _signProof(
string memory name,
uint256 timestamp,
address owner
) internal returns (bytes memory signature) {
return _signProof(signerPk, name, timestamp, owner);
}

function _signProof(
uint256 pk,
string memory name,
uint256 timestamp,
address owner
) internal returns (bytes memory signature) {
bytes32 eip712hash = resolver.hashTypedDataV4(
keccak256(abi.encode(resolver.usernameProofTypehash(), keccak256(bytes(name)), timestamp, owner))
);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(pk, eip712hash);
signature = abi.encodePacked(r, s, v);
assertEq(signature.length, 65);
}
}
Loading
Loading