diff --git a/contracts/utils/TimestampedHashRegistry.sol b/contracts/utils/TimestampedHashRegistry.sol index f031182..f873008 100644 --- a/contracts/utils/TimestampedHashRegistry.sol +++ b/contracts/utils/TimestampedHashRegistry.sol @@ -19,7 +19,9 @@ contract TimestampedHashRegistry is mapping(bytes32 => EnumerableSet.AddressSet) private _hashTypeToSigners; - mapping(bytes32 => SignedHash) public hashTypeToSignedHash; + mapping(bytes32 => bytes32) public hashTypeToHash; + + mapping(bytes32 => uint256) public hashTypeToTimestamp; bytes32 private constant _SIGNED_HASH_TYPE_HASH = keccak256( @@ -32,9 +34,7 @@ contract TimestampedHashRegistry is require(hashType != bytes32(0), "Hash type is zero"); require(signer != address(0), "Signer is zero"); require( - _hashTypeToSigners[keccak256(abi.encodePacked(hashType))].add( - signer - ), + _hashTypeToSigners[hashType].add(signer), "Signer already exists" ); emit AddedSigner(hashType, signer); @@ -44,9 +44,7 @@ contract TimestampedHashRegistry is require(hashType != bytes32(0), "Hash type is zero"); require(signer != address(0), "Signer is zero"); require( - _hashTypeToSigners[keccak256(abi.encodePacked(hashType))].remove( - signer - ), + _hashTypeToSigners[hashType].remove(signer), "Signer does not exist" ); emit RemovedSigner(hashType, signer); @@ -55,19 +53,17 @@ contract TimestampedHashRegistry is function getSigners( bytes32 hashType ) external view returns (address[] memory signers) { - signers = _hashTypeToSigners[keccak256(abi.encodePacked(hashType))] - .values(); + signers = _hashTypeToSigners[hashType].values(); } - function registerSignedHash( + function registerHash( bytes32 hashType, - SignedHash calldata signedHash, + bytes32 hash, + uint256 timestamp, bytes[] calldata signatures ) external { require(hashType != bytes32(0), "Hash type is zero"); - EnumerableSet.AddressSet storage signers = _hashTypeToSigners[ - keccak256(abi.encodePacked(hashType)) - ]; + EnumerableSet.AddressSet storage signers = _hashTypeToSigners[hashType]; require(signers.length() != 0, "Signers have not been set"); require( signatures.length == signers.length(), @@ -80,21 +76,16 @@ contract TimestampedHashRegistry is abi.encode( _SIGNED_HASH_TYPE_HASH, hashType, - signedHash.hash, - signedHash.timestamp + hash, + timestamp ) ) ).recover(signatures[ind]) == signers.at(ind), "Signature mismatch" ); } - hashTypeToSignedHash[ - keccak256(abi.encodePacked(hashType)) - ] = SignedHash(signedHash.hash, signedHash.timestamp); - emit RegisteredSignedHash( - hashType, - signedHash.hash, - signedHash.timestamp - ); + hashTypeToHash[hashType] = hash; + hashTypeToTimestamp[hashType] = timestamp; + emit RegisteredHash(hashType, hash, timestamp); } } diff --git a/contracts/utils/interfaces/ITimestampedHashRegistry.sol b/contracts/utils/interfaces/ITimestampedHashRegistry.sol index c932f27..56a541c 100644 --- a/contracts/utils/interfaces/ITimestampedHashRegistry.sol +++ b/contracts/utils/interfaces/ITimestampedHashRegistry.sol @@ -6,17 +6,12 @@ interface ITimestampedHashRegistry { event RemovedSigner(bytes32 indexed hashType, address signer); - event RegisteredSignedHash( + event RegisteredHash( bytes32 indexed hashType, bytes32 hash, uint256 timestamp ); - struct SignedHash { - bytes32 hash; // i.e. merkle tree root - uint256 timestamp; - } - function addSigner(bytes32 hashType, address signer) external; function removeSigner(bytes32 hashType, address signer) external; @@ -25,13 +20,18 @@ interface ITimestampedHashRegistry { bytes32 hashType ) external view returns (address[] memory signers); - function registerSignedHash( + function registerHash( bytes32 hashType, - SignedHash calldata signedHash, + bytes32 hash, + uint256 timestamp, bytes[] calldata signatures ) external; - function hashTypeToSignedHash( + function hashTypeToHash( + bytes32 hashType + ) external view returns (bytes32 hash); + + function hashTypeToTimestamp( bytes32 hashType - ) external view returns (bytes32 hash, uint256 timestamp); + ) external view returns (uint256 timestamp); } diff --git a/test/utils/TimestampedHashRegistry.sol.js b/test/utils/TimestampedHashRegistry.sol.js index a3ff2d8..d0ec472 100644 --- a/test/utils/TimestampedHashRegistry.sol.js +++ b/test/utils/TimestampedHashRegistry.sol.js @@ -52,7 +52,7 @@ describe('TimestampedHashRegistry', function () { { name: 'timestamp', type: 'uint256' }, ], }; - const dapiFallbackHashType = hre.ethers.utils.formatBytes32String('dAPI fallback root'); + const dapiFallbackHashType = hre.ethers.utils.solidityKeccak256(['string'], ['dAPI fallback root']); const values = { hashType: dapiFallbackHashType, hash: root, @@ -275,7 +275,7 @@ describe('TimestampedHashRegistry', function () { }); }); - describe('registerSignedHash', function () { + describe('registerHash', function () { context('Hash type is not zero', function () { context('Signers is not empty', function () { context('Number of signatures is equal to number of signers', function () { @@ -288,10 +288,10 @@ describe('TimestampedHashRegistry', function () { roles.dapiFallbackRootSigner2.address, roles.dapiFallbackRootSigner3.address, ]; - expect(await timestampedHashRegistry.hashTypeToSignedHash(dapiFallbackHashType)).to.contain( - hre.ethers.constants.HashZero, - 0 + expect(await timestampedHashRegistry.hashTypeToHash(dapiFallbackHashType)).to.equal( + hre.ethers.constants.HashZero ); + expect(await timestampedHashRegistry.hashTypeToTimestamp(dapiFallbackHashType)).to.equal(0); await timestampedHashRegistry .connect(roles.owner) .multicall( @@ -299,14 +299,11 @@ describe('TimestampedHashRegistry', function () { timestampedHashRegistry.interface.encodeFunctionData('addSigner', [dapiFallbackHashType, signer]) ) ); - await expect( - timestampedHashRegistry.registerSignedHash(dapiFallbackHashType, { hash: root, timestamp }, signatures) - ) - .to.emit(timestampedHashRegistry, 'RegisteredSignedHash') + await expect(timestampedHashRegistry.registerHash(dapiFallbackHashType, root, timestamp, signatures)) + .to.emit(timestampedHashRegistry, 'RegisteredHash') .withArgs(dapiFallbackHashType, root, timestamp); - expect( - await timestampedHashRegistry.hashTypeToSignedHash(hre.ethers.utils.keccak256(dapiFallbackHashType)) - ).to.contain(root, timestamp); + expect(await timestampedHashRegistry.hashTypeToHash(dapiFallbackHashType)).to.equal(root); + expect(await timestampedHashRegistry.hashTypeToTimestamp(dapiFallbackHashType)).to.equal(timestamp); }); }); context('All signatures do not match', function () { @@ -335,7 +332,7 @@ describe('TimestampedHashRegistry', function () { ); // Signed by a different signer await expect( - timestampedHashRegistry.registerSignedHash(dapiFallbackHashType, { hash: root, timestamp }, [ + timestampedHashRegistry.registerHash(dapiFallbackHashType, root, timestamp, [ await roles.randomPerson._signTypedData(domain, types, { hashType: dapiFallbackHashType, hash: root, @@ -346,7 +343,7 @@ describe('TimestampedHashRegistry', function () { ).to.be.revertedWith('Signature mismatch'); // Signed a different root await expect( - timestampedHashRegistry.registerSignedHash(dapiFallbackHashType, { hash: root, timestamp }, [ + timestampedHashRegistry.registerHash(dapiFallbackHashType, root, timestamp, [ await roles.dapiFallbackRootSigner1._signTypedData(domain, types, { hashType: dapiFallbackHashType, hash: generateRandomBytes32(), @@ -357,19 +354,16 @@ describe('TimestampedHashRegistry', function () { ).to.be.revertedWith('Signature mismatch'); // All signatures are different await expect( - timestampedHashRegistry.registerSignedHash( + timestampedHashRegistry.registerHash( dapiFallbackHashType, - { hash: root, timestamp }, + root, + timestamp, Array(3).fill(signatures[0]) ) ).to.be.revertedWith('Signature mismatch'); // All signatures are in the expected order await expect( - timestampedHashRegistry.registerSignedHash( - dapiFallbackHashType, - { hash: root, timestamp }, - signatures.reverse() - ) + timestampedHashRegistry.registerHash(dapiFallbackHashType, root, timestamp, signatures.reverse()) ).to.be.revertedWith('Signature mismatch'); }); }); @@ -391,11 +385,7 @@ describe('TimestampedHashRegistry', function () { ) ); await expect( - timestampedHashRegistry.registerSignedHash( - dapiFallbackHashType, - { hash: root, timestamp }, - signatures.slice(1) - ) + timestampedHashRegistry.registerHash(dapiFallbackHashType, root, timestamp, signatures.slice(1)) ).to.be.revertedWith('Invalid number of signatures'); }); }); @@ -404,7 +394,7 @@ describe('TimestampedHashRegistry', function () { it('reverts', async function () { const { timestampedHashRegistry, dapiFallbackHashType, root, timestamp } = await helpers.loadFixture(deploy); await expect( - timestampedHashRegistry.registerSignedHash(dapiFallbackHashType, { hash: root, timestamp }, []) + timestampedHashRegistry.registerHash(dapiFallbackHashType, root, timestamp, []) ).to.be.revertedWith('Signers have not been set'); }); }); @@ -413,11 +403,7 @@ describe('TimestampedHashRegistry', function () { it('reverts', async function () { const { timestampedHashRegistry, root, timestamp, signatures } = await helpers.loadFixture(deploy); await expect( - timestampedHashRegistry.registerSignedHash( - hre.ethers.constants.HashZero, - { hash: root, timestamp }, - signatures - ) + timestampedHashRegistry.registerHash(hre.ethers.constants.HashZero, root, timestamp, signatures) ).to.be.revertedWith('Hash type is zero'); }); });