generated from ScopeLift/foundry-template
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add initial version of ERC6538Registry and tests (#3)
Adds a first implementation of the ERC-6538 Registry contract. It does not yet implement the `registerKeysOnBehalf` methods, which will be done in a future PR.
- Loading branch information
Showing
5 changed files
with
180 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity 0.8.20; | ||
|
||
import {IERC6538Registry} from "./interfaces/IERC6538Registry.sol"; | ||
|
||
/// @dev `ERC6538Registry` contract to map accounts to their stealth meta-address. See | ||
/// [ERC-6538](https://eips.ethereum.org/EIPS/eip-6538) to learn more. | ||
contract ERC6538Registry is IERC6538Registry { | ||
/// @notice Maps a registrant's identifier to the scheme ID to the stealth meta-address. | ||
/// @dev `registrant` may be a standard 160-bit address or any other identifier. | ||
/// @dev `schemeId` is an integer identifier for the stealth address scheme. | ||
mapping(bytes registrant => mapping(uint256 schemeId => bytes)) public stealthMetaAddressOf; | ||
|
||
/// @inheritdoc IERC6538Registry | ||
function registerKeys(uint256 schemeId, bytes memory stealthMetaAddress) external { | ||
bytes memory registrant = _toBytes(msg.sender); | ||
stealthMetaAddressOf[registrant][schemeId] = stealthMetaAddress; | ||
emit StealthMetaAddressSet(registrant, schemeId, stealthMetaAddress); | ||
} | ||
|
||
/// @inheritdoc IERC6538Registry | ||
function registerKeysOnBehalf( | ||
address registrant, | ||
uint256 schemeId, | ||
bytes memory signature, | ||
bytes memory stealthMetaAddress | ||
) external pure { | ||
registerKeysOnBehalf(_toBytes(registrant), schemeId, signature, stealthMetaAddress); | ||
} | ||
|
||
/// @inheritdoc IERC6538Registry | ||
function registerKeysOnBehalf( | ||
bytes memory, // registrant | ||
uint256, // schemeId | ||
bytes memory, // signature | ||
bytes memory // stealthMetaAddress | ||
) public pure { | ||
revert("not implemented"); | ||
} | ||
|
||
/// @dev Converts an `address` to `bytes`. | ||
function _toBytes(address who) internal pure returns (bytes memory) { | ||
return bytes.concat(bytes32(uint256(uint160(who)))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.0; | ||
|
||
/// @dev Interface for calling the `ERC6538Registry` contract to map accounts to their stealth | ||
/// meta-address. See [ERC-6538](https://eips.ethereum.org/EIPS/eip-6538) to learn more. | ||
interface IERC6538Registry { | ||
/// @dev Emitted when a registrant updates their stealth meta-address. | ||
/// @param registrant The account that registered the stealth meta-address. | ||
/// @param schemeId Identifier corresponding to the applied stealth address scheme, e.g. 0 for | ||
/// secp256k1, as specified in ERC-5564. | ||
/// @param stealthMetaAddress The stealth meta-address. | ||
/// [ERC-5564](https://eips.ethereum.org/EIPS/eip-5564) bases the format for stealth | ||
/// meta-addresses on [ERC-3770](https://eips.ethereum.org/EIPS/eip-3770) and specifies them as: | ||
/// st:<shortName>:0x<spendingPubKey>:<viewingPubKey> | ||
/// The chain (`shortName`) is implicit based on the chain the `ERC6538Registry` is deployed on, | ||
/// therefore this `stealthMetaAddress` is just the `spendingPubKey` and `viewingPubKey` | ||
/// concatenated. | ||
event StealthMetaAddressSet( | ||
bytes indexed registrant, uint256 indexed schemeId, bytes stealthMetaAddress | ||
); | ||
|
||
/// @notice Sets the caller's stealth meta-address for the given scheme ID. | ||
/// @param schemeId Identifier corresponding to the applied stealth address scheme, e.g. 0 for | ||
/// secp256k1, as specified in ERC-5564. | ||
/// @param stealthMetaAddress The stealth meta-address to register. | ||
function registerKeys(uint256 schemeId, bytes memory stealthMetaAddress) external; | ||
|
||
/// @notice Sets the `registrant`'s stealth meta-address for the given scheme ID. | ||
/// @param registrant Address of the registrant. | ||
/// @param schemeId Identifier corresponding to the applied stealth address scheme, e.g. 0 for | ||
/// secp256k1, as specified in ERC-5564. | ||
/// @param signature A signature from the `registrant` authorizing the registration. | ||
/// @param stealthMetaAddress The stealth meta-address to register. | ||
/// @dev Supports both EOA signatures and EIP-1271 signatures. | ||
/// @dev Reverts if the signature is invalid. | ||
function registerKeysOnBehalf( | ||
address registrant, | ||
uint256 schemeId, | ||
bytes memory signature, | ||
bytes memory stealthMetaAddress | ||
) external; | ||
|
||
/// @notice Sets the `registrant`s stealth meta-address for the given scheme ID. | ||
/// @param registrant Recipient identifier, such as an address. | ||
/// @param schemeId Identifier corresponding to the applied stealth address scheme, e.g. 0 for | ||
/// secp256k1, as specified in ERC-5564. | ||
/// @param signature A signature from the `registrant` authorizing the registration. | ||
/// @param stealthMetaAddress The stealth meta-address to register. | ||
/// @dev Supports both EOA signatures and EIP-1271 signatures. | ||
/// @dev Reverts if the signature is invalid. | ||
function registerKeysOnBehalf( | ||
bytes memory registrant, | ||
uint256 schemeId, | ||
bytes memory signature, | ||
bytes memory stealthMetaAddress | ||
) external; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity 0.8.20; | ||
|
||
import {Test} from "forge-std/Test.sol"; | ||
import {Deploy} from "script/Deploy.s.sol"; | ||
|
||
contract ERC6538RegistryTest is Test, Deploy { | ||
event StealthMetaAddressSet( | ||
bytes indexed registrant, uint256 indexed schemeId, bytes stealthMetaAddress | ||
); | ||
|
||
function setUp() public { | ||
Deploy.run(); | ||
} | ||
|
||
function toBytes(address who) internal pure returns (bytes memory) { | ||
return bytes.concat(bytes32(uint256(uint160(who)))); | ||
} | ||
} | ||
|
||
contract RegisterKeys is ERC6538RegistryTest { | ||
function testFuzz_EmitsStealthMetaAddressSetEvent( | ||
address caller, | ||
uint256 schemeId, | ||
bytes memory stealthMetaAddress | ||
) external { | ||
vm.prank(caller); | ||
vm.expectEmit(); | ||
emit StealthMetaAddressSet(toBytes(caller), schemeId, stealthMetaAddress); | ||
registry.registerKeys(schemeId, stealthMetaAddress); | ||
} | ||
|
||
function testFuzz_CorrectlyMapsRegistrantToSchemeIdToStealthMetaAddressInStorage( | ||
address caller, | ||
uint256 schemeId, | ||
bytes memory stealthMetaAddress | ||
) external { | ||
assertEq(registry.stealthMetaAddressOf(toBytes(caller), schemeId), ""); | ||
vm.prank(caller); | ||
registry.registerKeys(schemeId, stealthMetaAddress); | ||
assertEq(registry.stealthMetaAddressOf(toBytes(caller), schemeId), stealthMetaAddress); | ||
} | ||
|
||
// This test is a subset of `testFuzz_EmitsStealthMetaAddressSetEvent`, and is mainly present to | ||
// make the `announce` method's specification more explicit. For this reason, we set the number of | ||
// runs to 1 for all profiles. | ||
/// forge-config: default.fuzz.runs = 1 | ||
/// forge-config: ci.fuzz.runs = 1 | ||
/// forge-config: lite.fuzz.runs = 1 | ||
function testFuzz_NeverReverts(address caller, uint256 schemeId, bytes memory stealthMetaAddress) | ||
external | ||
{ | ||
vm.prank(caller); | ||
registry.registerKeys(schemeId, stealthMetaAddress); | ||
} | ||
} | ||
|
||
contract RegisterKeysOnBehalf_Address is ERC6538RegistryTest { | ||
function test_NotImplemented() external { | ||
vm.expectRevert("not implemented"); | ||
registry.registerKeysOnBehalf(address(0), 0, "", ""); | ||
} | ||
} | ||
|
||
contract RegisterKeysOnBehalf_Bytes is ERC6538RegistryTest { | ||
function test_NotImplemented() external { | ||
vm.expectRevert("not implemented"); | ||
registry.registerKeysOnBehalf(bytes("0"), 0, "", ""); | ||
} | ||
} |