Skip to content

Commit 6d87752

Browse files
authored
Improve Reverse Resolver Introspection (#498)
* bumped @unruggable/gateways @namestone/ezccip and ethers * expanded INameReverser — now sufficient to identify a "reverse" resolver * added IVerifiableResolver to ChainReverseResolver * reduced some duplicated constants * added fuzz test
1 parent 0ad6af3 commit 6d87752

File tree

14 files changed

+276
-94
lines changed

14 files changed

+276
-94
lines changed

bun.lock

Lines changed: 18 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contracts/reverseResolver/AbstractReverseResolver.sol

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ abstract contract AbstractReverseResolver is
1414
INameReverser,
1515
ERC165
1616
{
17-
/// @notice The coin type for the resolver.
17+
/// @inheritdoc INameReverser
1818
uint256 public immutable coinType;
1919

20-
/// @notice The address returned by `addr(coinType)` for the resolver.
21-
address private immutable registrar;
20+
/// @inheritdoc INameReverser
21+
address public immutable chainRegistrar;
2222

2323
/// @notice `resolve()` was called with a profile other than `name()` or `addr(*)`.
2424
/// @dev Error selector: `0x7b1c461b`
@@ -28,22 +28,22 @@ abstract contract AbstractReverseResolver is
2828
/// @dev Error selector: `0x5fe9a5df`
2929
error UnreachableName(bytes name);
3030

31-
constructor(uint256 _coinType, address _registrar) {
31+
constructor(uint256 _coinType, address registrar) {
3232
coinType = _coinType;
33-
registrar = _registrar;
33+
chainRegistrar = registrar;
3434
}
3535

3636
/// @inheritdoc ERC165
3737
function supportsInterface(
3838
bytes4 interfaceId
39-
) public view override returns (bool) {
39+
) public view virtual override returns (bool) {
4040
return
4141
interfaceId == type(IExtendedResolver).interfaceId ||
4242
interfaceId == type(INameReverser).interfaceId ||
4343
super.supportsInterface(interfaceId);
4444
}
4545

46-
/// @notice The EVM Chain ID corresponding to the `coinType`.
46+
/// @inheritdoc INameReverser
4747
function chainId() external view returns (uint32) {
4848
return ENSIP19.chainFromCoinType(coinType);
4949
}
@@ -86,14 +86,14 @@ abstract contract AbstractReverseResolver is
8686
(bool valid, ) = ENSIP19.parseNamespace(name, 0);
8787
if (!valid) revert UnreachableName(name);
8888
return
89-
abi.encode(coinType == COIN_TYPE_ETH ? registrar : address(0));
89+
abi.encode(coinType == COIN_TYPE_ETH ? chainRegistrar : address(0));
9090
} else if (selector == IAddressResolver.addr.selector) {
9191
(bool valid, ) = ENSIP19.parseNamespace(name, 0);
9292
if (!valid) revert UnreachableName(name);
9393
(, uint256 ct) = abi.decode(data[4:], (bytes32, uint256));
9494
return
9595
abi.encode(
96-
coinType == ct ? abi.encodePacked(registrar) : new bytes(0)
96+
coinType == ct ? abi.encodePacked(chainRegistrar) : new bytes(0)
9797
);
9898
} else {
9999
revert UnsupportedResolverProfile(selector);

contracts/reverseResolver/ChainReverseResolver.sol

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity ^0.8.17;
33

4+
import {ERC165} from "@openzeppelin/contracts-v5/utils/introspection/ERC165.sol";
45
import {Ownable} from "@openzeppelin/contracts-v5/access/Ownable.sol";
56

67
import {GatewayFetchTarget, IGatewayVerifier} from "@unruggable/gateways/GatewayFetchTarget.sol";
78
import {GatewayFetcher, GatewayRequest, RequestOverflow} from "@unruggable/gateways/GatewayFetcher.sol";
89

910
import {AbstractReverseResolver} from "./AbstractReverseResolver.sol";
1011
import {IStandaloneReverseRegistrar} from "../reverseRegistrar/IStandaloneReverseRegistrar.sol";
12+
import {IVerifiableResolver} from "../resolvers/profiles/IVerifiableResolver.sol";
1113
import {INameReverser} from "./INameReverser.sol";
14+
import {ENSIP19} from "../utils/ENSIP19.sol";
1215

1316
/// @title Chain Reverse Resolver
1417
/// @notice Reverses an EVM address using the first non-null response from the following sources:
15-
/// 1. `L2ReverseRegistrar` on L2 chain via Unruggable Gateway
16-
/// 2. `IStandaloneReverseRegistrar` for "default.reverse"
18+
///
19+
/// 1. `L2ReverseRegistrar` on L2 chain via Unruggable Gateway
20+
/// 2. `IStandaloneReverseRegistrar` for "default.reverse"
21+
///
1722
contract ChainReverseResolver is
1823
AbstractReverseResolver,
24+
IVerifiableResolver,
1925
GatewayFetchTarget,
2026
Ownable
2127
{
@@ -27,9 +33,6 @@ contract ChainReverseResolver is
2733
/// @notice The reverse registrar contract for "default.reverse".
2834
IStandaloneReverseRegistrar public immutable defaultRegistrar;
2935

30-
/// @notice The reverse registrar address on the L2 chain.
31-
address public immutable l2Registrar;
32-
3336
/// @notice The verifier contract for the L2 chain.
3437
IGatewayVerifier public gatewayVerifier;
3538

@@ -46,16 +49,34 @@ contract ChainReverseResolver is
4649
address _owner,
4750
uint256 coinType,
4851
IStandaloneReverseRegistrar _defaultRegistrar,
49-
address _l2Registrar,
52+
address _chainRegistrar,
5053
IGatewayVerifier verifier,
5154
string[] memory gateways
52-
) Ownable(_owner) AbstractReverseResolver(coinType, _l2Registrar) {
55+
) Ownable(_owner) AbstractReverseResolver(coinType, _chainRegistrar) {
5356
defaultRegistrar = _defaultRegistrar;
54-
l2Registrar = _l2Registrar;
5557
gatewayVerifier = verifier;
5658
gatewayURLs = gateways;
5759
}
5860

61+
/// @inheritdoc ERC165
62+
function supportsInterface(
63+
bytes4 interfaceId
64+
) public view override returns (bool) {
65+
return
66+
interfaceId == type(IVerifiableResolver).interfaceId ||
67+
super.supportsInterface(interfaceId);
68+
}
69+
70+
/// @inheritdoc IVerifiableResolver
71+
function verifierMetadata(
72+
bytes memory name
73+
) external view returns (address verifier, string[] memory gateways) {
74+
(bytes memory a, uint256 ct) = ENSIP19.parse(name);
75+
if (a.length == 20 && ct == coinType) {
76+
return (address(gatewayVerifier), gatewayURLs);
77+
}
78+
}
79+
5980
/// @notice Set gateway URLs.
6081
/// @param gateways The new gateway URLs.
6182
function setGatewayURLs(string[] memory gateways) external onlyOwner {
@@ -75,7 +96,7 @@ contract ChainReverseResolver is
7596
address addr
7697
) internal view override returns (string memory) {
7798
GatewayRequest memory req = GatewayFetcher.newRequest(1);
78-
req.setTarget(l2Registrar); // target L2 registrar
99+
req.setTarget(chainRegistrar);
79100
req.setSlot(NAMES_SLOT).push(addr).follow().readBytes(); // names[addr]
80101
req.setOutput(0);
81102
fetch(
@@ -118,8 +139,8 @@ contract ChainReverseResolver is
118139
GatewayRequest memory req = GatewayFetcher.newRequest(
119140
uint8(addrs.length)
120141
);
121-
req.setTarget(l2Registrar); // target L2 registrar
122-
for (uint256 i; i < addrs.length; i++) {
142+
req.setTarget(chainRegistrar); // target L2 registrar
143+
for (uint256 i; i < addrs.length; ++i) {
123144
req.setSlot(NAMES_SLOT).push(addrs[i]).follow().readBytes(); // names[addr[i]]
124145
req.setOutput(uint8(i));
125146
}
@@ -144,7 +165,7 @@ contract ChainReverseResolver is
144165
) external view returns (string[] memory names) {
145166
address[] memory addrs = abi.decode(extraData, (address[]));
146167
names = new string[](addrs.length);
147-
for (uint256 i; i < addrs.length; i++) {
168+
for (uint256 i; i < addrs.length; ++i) {
148169
string memory name = string(values[i]);
149170
if (bytes(name).length == 0) {
150171
name = defaultRegistrar.nameForAddr(addrs[i]);

contracts/reverseResolver/DefaultReverseResolver.sol

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,23 @@ import {COIN_TYPE_DEFAULT} from "../utils/ENSIP19.sol";
99
/// @title Default Reverse Resolver
1010
/// @notice Reverses an EVM address using the `IStandaloneReverseRegistrar` for "default.reverse".
1111
contract DefaultReverseResolver is AbstractReverseResolver {
12-
/// @notice The reverse registrar contract for "default.reverse".
13-
IStandaloneReverseRegistrar public immutable defaultRegistrar;
14-
1512
constructor(
16-
IStandaloneReverseRegistrar _defaultRegistrar
17-
) AbstractReverseResolver(COIN_TYPE_DEFAULT, address(_defaultRegistrar)) {
18-
defaultRegistrar = _defaultRegistrar;
19-
}
13+
IStandaloneReverseRegistrar defaultRegistrar
14+
) AbstractReverseResolver(COIN_TYPE_DEFAULT, address(defaultRegistrar)) {}
2015

2116
/// @inheritdoc AbstractReverseResolver
2217
function _resolveName(
2318
address addr
2419
) internal view override returns (string memory name) {
25-
name = defaultRegistrar.nameForAddr(addr);
20+
name = IStandaloneReverseRegistrar(chainRegistrar).nameForAddr(addr);
2621
}
2722

2823
/// @inheritdoc INameReverser
2924
function resolveNames(
3025
address[] memory addrs
3126
) external view returns (string[] memory names) {
3227
names = new string[](addrs.length);
33-
for (uint256 i; i < addrs.length; i++) {
28+
for (uint256 i; i < addrs.length; ++i) {
3429
names[i] = _resolveName(addrs[i]);
3530
}
3631
}

0 commit comments

Comments
 (0)