Skip to content

Commit a3174a7

Browse files
authored
feat: implements resolve (#11)
Closes EFI-430, EFI-439
1 parent b9476c1 commit a3174a7

4 files changed

Lines changed: 74 additions & 2 deletions

File tree

src/contracts/L2Resolver.sol

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,23 @@ contract L2Resolver is IL2Resolver, IERC165 {
102102
_chainId = this.getRecord(_node, CHAIN_IDENTIFIER_EIP7930_KEY);
103103
}
104104

105+
/// @inheritdoc IL2Resolver
106+
function resolve(bytes calldata, bytes calldata _data) external view returns (bytes memory _result) {
107+
bytes4 _selector = bytes4(_data);
108+
109+
if (_selector == this.chainId.selector) {
110+
(, bytes32 _node) = abi.decode(_data, (bytes4, bytes32));
111+
return abi.encode(this.chainId(_node));
112+
}
113+
114+
if (_selector == this.chainName.selector) {
115+
(, bytes memory _chainIdBytes) = abi.decode(_data, (bytes4, bytes));
116+
return abi.encode(this.chainName(_chainIdBytes));
117+
}
118+
119+
revert UnsupportedFunctionSelector();
120+
}
121+
105122
/// @inheritdoc IERC165
106123
function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool _isSupported) {
107124
_isSupported = _interfaceId == type(IERC165).interfaceId || _interfaceId == type(IExtendedResolver).interfaceId;

src/interfaces/IL2Resolver.sol

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ interface IL2Resolver {
3535
*/
3636
error AddressCannotBeZero();
3737

38+
/**
39+
* @notice Thrown when calling resolve with an unsupported function selector.
40+
*/
41+
error UnsupportedFunctionSelector();
42+
3843
/*///////////////////////////////////////////////////////////////
3944
LOGIC
4045
//////////////////////////////////////////////////////////////*/
@@ -71,6 +76,22 @@ interface IL2Resolver {
7176
*/
7277
function chainName(bytes calldata _chainIdBytes) external view returns (string memory _chainName);
7378

79+
/**
80+
* @notice Implements the ENSIP-10 Extended Resolver interface.
81+
* @notice Routes calls to other specific view functions on this resolver based on the function selector
82+
* found in the data parameter.
83+
* @param _name DNS-encoded full version of the name being resolved (e.g., dnsencode("optimism.l2.eth")).
84+
* @param _data Contains the ABI-encoded function selector and arguments for the actual data being requested.
85+
* @dev Currently supports routing to:
86+
* - this.chainId(node): If data contains the selector and ABI-encoded arguments for chainId(bytes32).
87+
* The node argument is decoded by the resolver from the data parameter.
88+
* - this.chainName(chainIdentifierBytes): If data contains the selector and ABI-encoded arguments for
89+
* chainName(bytes). The chainIdentifierBytes argument is decoded by the resolver from the data parameter.
90+
* @return _result Returns the ABI-encoded result of the target function, or reverts if the data does not
91+
* correspond to a supported function or if resolution fails.
92+
*/
93+
function resolve(bytes calldata _name, bytes calldata _data) external view returns (bytes memory _result);
94+
7495
/*///////////////////////////////////////////////////////////////
7596
VARIABLES
7697
//////////////////////////////////////////////////////////////*/

test/unit/L2Resolver.t.sol

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,19 @@ import {IL2Resolver} from 'src/interfaces/IL2Resolver.sol';
1313
import {INameWrapper} from 'src/interfaces/INameWrapper.sol';
1414

1515
contract UnitL2Resolver is Test {
16+
string internal constant _ENS_DOMAIN = 'optimism.l2.eth';
1617
L2Resolver internal _l2Resolver;
1718
address internal _ensRegistry = makeAddr('ENSRegistry');
1819
address internal _nameWrapper = makeAddr('NameWrapper');
1920
address internal _reverseAdmin = makeAddr('ReverseAdmin');
2021
address internal _nodeOwner = makeAddr('NodeOwner');
2122
bytes32 internal _parentNodeNameHash = keccak256('l2.eth');
2223
bytes32 internal _reverseLookupNode;
23-
bytes32 internal _nodeNameHash = keccak256('optimism.l2.eth');
24+
bytes32 internal _nodeNameHash = keccak256(abi.encode(_ENS_DOMAIN));
2425
string internal _key;
2526
bytes internal _chainIdBytes = hex'00010001010A00';
2627
string internal _reverseLookupKey;
27-
bytes internal _reverseLookupValue = abi.encode('optimism.l2.eth');
28+
bytes internal _reverseLookupValue = abi.encode(_ENS_DOMAIN);
2829

2930
function setUp() external {
3031
_l2Resolver = new L2Resolver(_ensRegistry, _nameWrapper, _reverseAdmin, _parentNodeNameHash);
@@ -394,6 +395,7 @@ contract UnitL2Resolver is Test {
394395
bytes memory _domainChainIdBytes
395396
) external {
396397
vm.assume(bytes(_ensDomain).length > 0);
398+
397399
bytes memory _value = abi.encode(_ensDomain);
398400
string memory _reverseKey = string.concat(_key, _bytes32ToHexString(keccak256(_domainChainIdBytes)));
399401

@@ -409,6 +411,30 @@ contract UnitL2Resolver is Test {
409411
assertEq(_l2Resolver.chainName(_chainIdBytes), '');
410412
}
411413

414+
function test_ResolveWhenResolvingChainId(bytes calldata _name) external {
415+
_setRecord(_nodeNameHash, _key, _chainIdBytes);
416+
417+
// it returns abi-encoded chain identifier
418+
bytes memory _data = abi.encode(IL2Resolver.chainId.selector, _nodeNameHash);
419+
assertEq(_l2Resolver.resolve(_name, _data), abi.encode(_chainIdBytes));
420+
}
421+
422+
function test_ResolveWhenResolvingChainName(bytes calldata _name) external {
423+
vm.prank(_reverseAdmin);
424+
_l2Resolver.setRecord(_reverseLookupNode, _reverseLookupKey, abi.encode(_ENS_DOMAIN));
425+
426+
// it returns abi-encoded ENS name
427+
bytes memory _data = abi.encode(IL2Resolver.chainName.selector, _chainIdBytes);
428+
assertEq(_l2Resolver.resolve(_name, _data), abi.encode(_ENS_DOMAIN));
429+
}
430+
431+
function test_ResolveWhenResolvingAnUnsupportedFunction(bytes calldata _name) external {
432+
// it reverts
433+
bytes memory _data = abi.encode(IL2Resolver.getRecord.selector, _nodeNameHash, _key);
434+
vm.expectRevert(abi.encodeWithSelector(IL2Resolver.UnsupportedFunctionSelector.selector));
435+
_l2Resolver.resolve(_name, _data);
436+
}
437+
412438
/**
413439
* @notice Sets up a mock and expects a call to it
414440
*

test/unit/L2Resolver.tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,11 @@ UnitL2Resolver::chainName
7373
│ └── it returns the primary ENS name
7474
└── when the reverse mapping does not exist
7575
└── it returns an empty string
76+
77+
UnitL2Resolver::resolve
78+
├── when resolving chainId
79+
│ └── it returns abi-encoded chain identifier
80+
├── when resolving chainName
81+
│ └── it returns abi-encoded ENS name
82+
└── when resolving an unsupported function
83+
└── it reverts

0 commit comments

Comments
 (0)