From d54b4b473dcece360a25fc5353e3f89ce4647677 Mon Sep 17 00:00:00 2001 From: katzman Date: Fri, 15 Nov 2024 12:51:35 -0800 Subject: [PATCH] Pubkey Resolver natspec and test --- src/L2/resolver/PubkeyResolver.sol | 38 ++++++++++++++-------- test/UpgradeableL2Resolver/SetName.t.sol | 4 +-- test/UpgradeableL2Resolver/SetPubkey.t.sol | 25 ++++++++++++++ 3 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 test/UpgradeableL2Resolver/SetPubkey.t.sol diff --git a/src/L2/resolver/PubkeyResolver.sol b/src/L2/resolver/PubkeyResolver.sol index fdf1450..f5feaca 100644 --- a/src/L2/resolver/PubkeyResolver.sol +++ b/src/L2/resolver/PubkeyResolver.sol @@ -5,38 +5,48 @@ import {IPubkeyResolver} from "ens-contracts/resolvers/profiles/IPubkeyResolver. import {ResolverBase} from "./ResolverBase.sol"; +/// @title Pubkey Resolver +/// +/// @notice Adaptation of the ENS PubkeyResolver.sol profile contract, with EIP-7201 storage compliance. +/// https://github.com/ensdomains/ens-contracts/blob/staging/contracts/resolvers/profiles/PubkeyResolver.sol +/// +/// @author Coinbase (https://github.com/base-org/basenames) abstract contract PubkeyResolver is IPubkeyResolver, ResolverBase { + /// @notice Tuple containing the x and y coordinates of a public key. struct PublicKey { bytes32 x; bytes32 y; } struct PubkeyResolverStorage { + /// @notice Public keys by node and version. mapping(uint64 version => mapping(bytes32 node => PublicKey pubkey)) versionable_pubkeys; } + /// @notice EIP-7201 storage location. // keccak256(abi.encode(uint256(keccak256("pubkey.resolver.storage")) - 1)) & ~bytes32(uint256(0xff)); bytes32 constant PUBKEY_RESOLVER_STORAGE = 0x59a318c6a4da81295c2a32b42a02c3db057bb9422e2eb1f6e516ee3694b1ef00; - /** - * Sets the SECP256k1 public key associated with an ENS node. - * @param node The ENS node to query - * @param x the X coordinate of the curve point for the public key. - * @param y the Y coordinate of the curve point for the public key. - */ + /// @notice Sets the SECP256k1 public key associated with an ENS node. + /// + /// @param node The ENS node to query. + /// + /// @param x the X coordinate of the curve point for the public key. + /// @param y the Y coordinate of the curve point for the public key. function setPubkey(bytes32 node, bytes32 x, bytes32 y) external virtual authorised(node) { _getPubkeyResolverStorage().versionable_pubkeys[_getResolverBaseStorage().recordVersions[node]][node] = PublicKey(x, y); emit PubkeyChanged(node, x, y); } - /** - * Returns the SECP256k1 public key associated with an ENS node. - * Defined in EIP 619. - * @param node The ENS node to query - * @return x The X coordinate of the curve point for the public key. - * @return y The Y coordinate of the curve point for the public key. - */ + /// @notice Returns the SECP256k1 public key associated with an ENS node. + /// + /// @dev See EIP-619. + /// + /// @param node The ENS node to query. + /// + /// @return x The X coordinate of the curve point for the public key. + /// @return y The Y coordinate of the curve point for the public key. function pubkey(bytes32 node) external view virtual override returns (bytes32 x, bytes32 y) { uint64 currentRecordVersion = _getResolverBaseStorage().recordVersions[node]; PubkeyResolverStorage storage $ = _getPubkeyResolverStorage(); @@ -44,10 +54,12 @@ abstract contract PubkeyResolver is IPubkeyResolver, ResolverBase { ($.versionable_pubkeys[currentRecordVersion][node].x, $.versionable_pubkeys[currentRecordVersion][node].y); } + /// @notice ERC-165 compliance. function supportsInterface(bytes4 interfaceID) public view virtual override returns (bool) { return interfaceID == type(IPubkeyResolver).interfaceId || super.supportsInterface(interfaceID); } + /// @notice EIP-7201 storage pointer fetch helper. function _getPubkeyResolverStorage() internal pure returns (PubkeyResolverStorage storage $) { assembly { $.slot := PUBKEY_RESOLVER_STORAGE diff --git a/test/UpgradeableL2Resolver/SetName.t.sol b/test/UpgradeableL2Resolver/SetName.t.sol index df839ea..14aeaca 100644 --- a/test/UpgradeableL2Resolver/SetName.t.sol +++ b/test/UpgradeableL2Resolver/SetName.t.sol @@ -11,11 +11,11 @@ contract SetName is UpgradeableL2ResolverBase { vm.prank(notUser); resolver.setName(node, name); } - + function test_setsTheName() public { vm.prank(user); resolver.setName(node, name); string memory retName = resolver.name(node); assertEq(keccak256(bytes(name)), keccak256(bytes(retName))); } -} \ No newline at end of file +} diff --git a/test/UpgradeableL2Resolver/SetPubkey.t.sol b/test/UpgradeableL2Resolver/SetPubkey.t.sol new file mode 100644 index 0000000..18ab711 --- /dev/null +++ b/test/UpgradeableL2Resolver/SetPubkey.t.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {UpgradeableL2ResolverBase} from "./UpgradeableL2ResolverBase.t.sol"; +import {ResolverBase} from "src/L2/resolver/ResolverBase.sol"; +import {PubkeyResolver} from "src/L2/resolver/PubkeyResolver.sol"; + +contract SetPubkey is UpgradeableL2ResolverBase { + bytes32 x = 0x65a2fa44daad46eab0278703edb6c4dcf5e30b8a9aec09fdc71a56f52aa392e4; + bytes32 y = 0x4a7a9e4604aa36898209997288e902ac544a555e4b5e0a9efef2b59233f3f437; + + function test_reverts_forUnauthorizedUser() public { + vm.expectRevert(abi.encodeWithSelector(ResolverBase.NotAuthorized.selector, node, notUser)); + vm.prank(notUser); + resolver.setPubkey(node, x, y); + } + + function test_setsThePubkey() public { + vm.prank(user); + resolver.setPubkey(node, x, y); + (bytes32 retX, bytes32 retY) = resolver.pubkey(node); + assertEq(retX, x); + assertEq(retY, y); + } +}