Skip to content

Commit f1fc41d

Browse files
committed
test: implements setRecord unit tests
1 parent 26003e7 commit f1fc41d

2 files changed

Lines changed: 356 additions & 5 deletions

File tree

test/unit/L2Resolver.t.sol

Lines changed: 322 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,342 @@ pragma solidity 0.8.30;
44
import {Test} from 'forge-std/Test.sol';
55
import {L2Resolver} from 'src/contracts/L2Resolver.sol';
66

7-
contract UnitL2Resolverconstructor is Test {
7+
import {IENS} from 'src/interfaces/IENS.sol';
8+
import {IL2Resolver} from 'src/interfaces/IL2Resolver.sol';
9+
import {INameWrapper} from 'src/interfaces/INameWrapper.sol';
10+
11+
contract UnitL2Resolver is Test {
812
L2Resolver internal _l2Resolver;
913
address internal _ensRegistry = makeAddr('ENSRegistry');
1014
address internal _nameWrapper = makeAddr('NameWrapper');
1115
address internal _reverseAdmin = makeAddr('ReverseAdmin');
12-
bytes32 internal _parentNode = bytes32(abi.encode('l2.eth'));
16+
bytes32 internal _parentNodeNameHash = keccak256('l2.eth');
17+
bytes32 internal _reverseLookupNode;
18+
bytes32 internal _nodeNameHash = keccak256('optimism.l2.eth');
19+
string internal _key;
20+
bytes internal _chainIdBytes = hex'00010001010A00';
21+
string internal _reverseLookupKey;
22+
bytes internal _reverseLookupValue = abi.encode('optimism.l2.eth');
1323

1424
function setUp() external {
15-
_l2Resolver = new L2Resolver(_ensRegistry, _nameWrapper, _reverseAdmin, _parentNode);
25+
_l2Resolver = new L2Resolver(_ensRegistry, _nameWrapper, _reverseAdmin, _parentNodeNameHash);
26+
_reverseLookupNode = _l2Resolver.REVERSE_LOOKUP_NODE();
27+
_key = _l2Resolver.CHAIN_IDENTIFIER_EIP7930_KEY();
28+
_reverseLookupKey = string.concat(_key, 'chainIdBytes');
29+
30+
vm.etch(address(_ensRegistry), new bytes(0x1));
31+
vm.etch(address(_nameWrapper), new bytes(0x1));
1632
}
1733

18-
function test_WhenDeployingTheContract() external view {
34+
function test_ConstructorWhenDeployingTheContract() external view {
1935
// it sets the ENS registry address
2036
assertEq(address(_l2Resolver.ENS_REGISTRY()), _ensRegistry);
2137
// it sets the name wrapper address
2238
assertEq(address(_l2Resolver.NAME_WRAPPER()), _nameWrapper);
2339
// it sets the reverse admin address
2440
assertEq(_l2Resolver.REVERSE_ADMIN(), _reverseAdmin);
2541
// it sets the parent node namehash
26-
assertEq(_l2Resolver.PARENT_NODE(), _parentNode);
42+
assertEq(_l2Resolver.PARENT_NODE(), _parentNodeNameHash);
43+
}
44+
45+
modifier whenTheNodeIsTheReverseLookupNode() {
46+
_;
47+
}
48+
49+
function test_SetRecordWhenTheCallerIsTheReverseAdmin() external {
50+
// it emits the RecordSet event
51+
vm.prank(_reverseAdmin);
52+
vm.expectEmit(true, true, false, true);
53+
emit IL2Resolver.RecordSet(_reverseLookupNode, _reverseLookupKey, _reverseLookupValue);
54+
_l2Resolver.setRecord(_reverseLookupNode, _reverseLookupKey, _reverseLookupValue);
55+
56+
// it sets the record
57+
assertEq(_l2Resolver.records(_reverseLookupNode, _reverseLookupKey), _reverseLookupValue);
58+
}
59+
60+
function test_SetRecordWhenTheCallerIsNotTheReverseAdmin(address _caller) external {
61+
vm.assume(_caller != _reverseAdmin);
62+
// it reverts
63+
vm.prank(_caller);
64+
vm.expectRevert(abi.encodeWithSelector(IL2Resolver.NotAuthorized.selector));
65+
_l2Resolver.setRecord(_reverseLookupNode, _reverseLookupKey, _reverseLookupValue);
66+
}
67+
68+
modifier whenTheNodeHasAnENSRegistryOwner(address _owner) {
69+
vm.mockCall(address(_ensRegistry), abi.encodeWithSelector(IENS.owner.selector, _nodeNameHash), abi.encode(_owner));
70+
vm.expectCall(address(_ensRegistry), abi.encodeWithSelector(IENS.owner.selector, _nodeNameHash));
71+
_;
72+
}
73+
74+
function test_SetRecordWhenTheCallerIsTheBeneficialOwner(address _caller)
75+
external
76+
whenTheNodeHasAnENSRegistryOwner(_caller)
77+
{
78+
vm.assume(_caller != _nameWrapper);
79+
vm.assume(_caller != address(0));
80+
81+
// it emits the RecordSet event
82+
vm.prank(_caller);
83+
vm.expectEmit(true, true, false, true);
84+
emit IL2Resolver.RecordSet(_nodeNameHash, _key, _chainIdBytes);
85+
_l2Resolver.setRecord(_nodeNameHash, _key, _chainIdBytes);
86+
87+
// it sets the record
88+
assertEq(_l2Resolver.records(_nodeNameHash, _key), _chainIdBytes);
89+
}
90+
91+
function test_SetRecordWhenTheCallerIsAnENSRegistryApprovedOperator(
92+
address _owner,
93+
address _caller
94+
) external whenTheNodeHasAnENSRegistryOwner(_owner) {
95+
vm.assume(_owner != _nameWrapper);
96+
vm.assume(_owner != address(0));
97+
vm.assume(_caller != _owner);
98+
99+
vm.mockCall(
100+
address(_ensRegistry), abi.encodeWithSelector(IENS.isApprovedForAll.selector, _owner, _caller), abi.encode(true)
101+
);
102+
vm.expectCall(address(_ensRegistry), abi.encodeWithSelector(IENS.isApprovedForAll.selector, _owner, _caller));
103+
104+
// it emits the RecordSet event
105+
vm.prank(_caller);
106+
vm.expectEmit(true, true, false, true);
107+
emit IL2Resolver.RecordSet(_nodeNameHash, _key, _chainIdBytes);
108+
_l2Resolver.setRecord(_nodeNameHash, _key, _chainIdBytes);
109+
110+
// it sets the record
111+
assertEq(_l2Resolver.records(_nodeNameHash, _key), _chainIdBytes);
112+
}
113+
114+
function test_SetRecordWhenTheCallerIsANameWrapperApprovedOperator(
115+
address _owner,
116+
address _caller
117+
) external whenTheNodeHasAnENSRegistryOwner(_nameWrapper) {
118+
vm.assume(_owner != address(0));
119+
vm.assume(_caller != _owner);
120+
121+
vm.mockCall(
122+
address(_nameWrapper), abi.encodeWithSelector(INameWrapper.ownerOf.selector, _nodeNameHash), abi.encode(_owner)
123+
);
124+
vm.expectCall(address(_nameWrapper), abi.encodeWithSelector(INameWrapper.ownerOf.selector, _nodeNameHash));
125+
vm.mockCall(
126+
address(_ensRegistry), abi.encodeWithSelector(IENS.isApprovedForAll.selector, _owner, _caller), abi.encode(false)
127+
);
128+
vm.expectCall(address(_ensRegistry), abi.encodeWithSelector(IENS.isApprovedForAll.selector, _owner, _caller));
129+
vm.mockCall(
130+
address(_nameWrapper),
131+
abi.encodeWithSelector(INameWrapper.isApprovedForAll.selector, _owner, _caller),
132+
abi.encode(true)
133+
);
134+
vm.expectCall(
135+
address(_nameWrapper), abi.encodeWithSelector(INameWrapper.isApprovedForAll.selector, _owner, _caller)
136+
);
137+
138+
// it emits the RecordSet event
139+
vm.prank(_caller);
140+
vm.expectEmit(true, true, false, true);
141+
emit IL2Resolver.RecordSet(_nodeNameHash, _key, _chainIdBytes);
142+
_l2Resolver.setRecord(_nodeNameHash, _key, _chainIdBytes);
143+
144+
// it sets the record
145+
assertEq(_l2Resolver.records(_nodeNameHash, _key), _chainIdBytes);
146+
}
147+
148+
function test_SetRecordWhenTheCallerIsNeitherOwnerNorApproved(
149+
address _owner,
150+
address _caller
151+
) external whenTheNodeHasAnENSRegistryOwner(_owner) {
152+
vm.assume(_owner != _caller);
153+
vm.assume(_owner != address(0));
154+
vm.assume(_owner != _nameWrapper);
155+
156+
vm.mockCall(
157+
address(_ensRegistry), abi.encodeWithSelector(IENS.isApprovedForAll.selector, _owner, _caller), abi.encode(false)
158+
);
159+
vm.expectCall(address(_ensRegistry), abi.encodeWithSelector(IENS.isApprovedForAll.selector, _owner, _caller));
160+
vm.mockCall(
161+
address(_nameWrapper),
162+
abi.encodeWithSelector(INameWrapper.isApprovedForAll.selector, _owner, _caller),
163+
abi.encode(false)
164+
);
165+
vm.expectCall(
166+
address(_nameWrapper), abi.encodeWithSelector(INameWrapper.isApprovedForAll.selector, _owner, _caller)
167+
);
168+
169+
// it reverts
170+
vm.prank(_caller);
171+
vm.expectRevert(abi.encodeWithSelector(IL2Resolver.NotAuthorized.selector));
172+
_l2Resolver.setRecord(_nodeNameHash, _key, _chainIdBytes);
173+
}
174+
175+
modifier whenTheNodeHasNoENSRegistryOwner() {
176+
vm.mockCall(
177+
address(_ensRegistry), abi.encodeWithSelector(IENS.owner.selector, _nodeNameHash), abi.encode(address(0))
178+
);
179+
vm.expectCall(address(_ensRegistry), abi.encodeWithSelector(IENS.owner.selector, _nodeNameHash));
180+
_;
181+
}
182+
183+
function test_SetRecordWhenTheCallerIsTheParentOwner(address _parentNodeOwner)
184+
external
185+
whenTheNodeHasNoENSRegistryOwner
186+
{
187+
vm.assume(_parentNodeOwner != address(0));
188+
vm.assume(_parentNodeOwner != _nameWrapper);
189+
190+
vm.mockCall(
191+
address(_ensRegistry),
192+
abi.encodeWithSelector(IENS.owner.selector, _parentNodeNameHash),
193+
abi.encode(_parentNodeOwner)
194+
);
195+
vm.expectCall(address(_ensRegistry), abi.encodeWithSelector(IENS.owner.selector, _parentNodeNameHash));
196+
197+
// it emits the RecordSet event
198+
vm.prank(_parentNodeOwner);
199+
vm.expectEmit(true, true, false, true);
200+
emit IL2Resolver.RecordSet(_nodeNameHash, _key, _chainIdBytes);
201+
_l2Resolver.setRecord(_nodeNameHash, _key, _chainIdBytes);
202+
203+
// it sets the record
204+
assertEq(_l2Resolver.records(_nodeNameHash, _key), _chainIdBytes);
205+
}
206+
207+
function test_SetRecordWhenTheCallerIsAnENSregistryApprovedOperatorOfTheParent(
208+
address _parentNodeOwner,
209+
address _caller
210+
) external whenTheNodeHasNoENSRegistryOwner {
211+
vm.assume(_parentNodeOwner != address(0));
212+
vm.assume(_parentNodeOwner != _nameWrapper);
213+
vm.assume(_caller != _parentNodeOwner);
214+
215+
vm.mockCall(
216+
address(_ensRegistry),
217+
abi.encodeWithSelector(IENS.owner.selector, _parentNodeNameHash),
218+
abi.encode(_parentNodeOwner)
219+
);
220+
vm.expectCall(address(_ensRegistry), abi.encodeWithSelector(IENS.owner.selector, _parentNodeNameHash));
221+
222+
vm.mockCall(
223+
address(_ensRegistry),
224+
abi.encodeWithSelector(IENS.isApprovedForAll.selector, _parentNodeOwner, _caller),
225+
abi.encode(true)
226+
);
227+
vm.expectCall(
228+
address(_ensRegistry), abi.encodeWithSelector(IENS.isApprovedForAll.selector, _parentNodeOwner, _caller)
229+
);
230+
231+
// it emits the RecordSet event
232+
vm.prank(_caller);
233+
vm.expectEmit(true, true, false, true);
234+
emit IL2Resolver.RecordSet(_nodeNameHash, _key, _chainIdBytes);
235+
_l2Resolver.setRecord(_nodeNameHash, _key, _chainIdBytes);
236+
237+
// it sets the record
238+
assertEq(_l2Resolver.records(_nodeNameHash, _key), _chainIdBytes);
239+
}
240+
241+
function test_SetRecordWhenTheCallerIsANameWrapperApprovedOperatorOfTheParent(
242+
address _parentNodeOwner,
243+
address _caller
244+
) external whenTheNodeHasNoENSRegistryOwner {
245+
vm.assume(_parentNodeOwner != address(0));
246+
vm.assume(_parentNodeOwner != _nameWrapper);
247+
vm.assume(_caller != _parentNodeOwner);
248+
249+
vm.mockCall(
250+
address(_ensRegistry), abi.encodeWithSelector(IENS.owner.selector, _parentNodeNameHash), abi.encode(_nameWrapper)
251+
);
252+
vm.expectCall(address(_ensRegistry), abi.encodeWithSelector(IENS.owner.selector, _parentNodeNameHash));
253+
vm.mockCall(
254+
address(_nameWrapper),
255+
abi.encodeWithSelector(INameWrapper.ownerOf.selector, _parentNodeNameHash),
256+
abi.encode(_parentNodeOwner)
257+
);
258+
vm.expectCall(address(_nameWrapper), abi.encodeWithSelector(INameWrapper.ownerOf.selector, _parentNodeNameHash));
259+
260+
vm.mockCall(
261+
address(_ensRegistry),
262+
abi.encodeWithSelector(IENS.isApprovedForAll.selector, _parentNodeOwner, _caller),
263+
abi.encode(false)
264+
);
265+
vm.expectCall(
266+
address(_ensRegistry), abi.encodeWithSelector(IENS.isApprovedForAll.selector, _parentNodeOwner, _caller)
267+
);
268+
269+
vm.mockCall(
270+
address(_nameWrapper),
271+
abi.encodeWithSelector(INameWrapper.isApprovedForAll.selector, _parentNodeOwner, _caller),
272+
abi.encode(true)
273+
);
274+
vm.expectCall(
275+
address(_nameWrapper), abi.encodeWithSelector(INameWrapper.isApprovedForAll.selector, _parentNodeOwner, _caller)
276+
);
277+
278+
// it emits the RecordSet event
279+
vm.prank(_caller);
280+
vm.expectEmit(true, true, false, true);
281+
emit IL2Resolver.RecordSet(_nodeNameHash, _key, _chainIdBytes);
282+
_l2Resolver.setRecord(_nodeNameHash, _key, _chainIdBytes);
283+
284+
// it sets the record
285+
assertEq(_l2Resolver.records(_nodeNameHash, _key), _chainIdBytes);
286+
}
287+
288+
function test_SetRecordWhenTheCallerIsNotAnApprovedOperatorOfTheParent(
289+
address _parentNodeOwner,
290+
address _caller
291+
) external whenTheNodeHasNoENSRegistryOwner {
292+
vm.assume(_parentNodeOwner != address(0));
293+
vm.assume(_parentNodeOwner != _nameWrapper);
294+
vm.assume(_caller != _parentNodeOwner);
295+
296+
vm.mockCall(
297+
address(_ensRegistry),
298+
abi.encodeWithSelector(IENS.owner.selector, _parentNodeNameHash),
299+
abi.encode(_parentNodeOwner)
300+
);
301+
vm.expectCall(address(_ensRegistry), abi.encodeWithSelector(IENS.owner.selector, _parentNodeNameHash));
302+
303+
vm.mockCall(
304+
address(_ensRegistry),
305+
abi.encodeWithSelector(IENS.isApprovedForAll.selector, _parentNodeOwner, _caller),
306+
abi.encode(false)
307+
);
308+
vm.expectCall(
309+
address(_ensRegistry), abi.encodeWithSelector(IENS.isApprovedForAll.selector, _parentNodeOwner, _caller)
310+
);
311+
312+
vm.mockCall(
313+
address(_nameWrapper),
314+
abi.encodeWithSelector(INameWrapper.isApprovedForAll.selector, _parentNodeOwner, _caller),
315+
abi.encode(false)
316+
);
317+
vm.expectCall(
318+
address(_nameWrapper), abi.encodeWithSelector(INameWrapper.isApprovedForAll.selector, _parentNodeOwner, _caller)
319+
);
320+
321+
// it reverts
322+
vm.prank(_caller);
323+
vm.expectRevert(abi.encodeWithSelector(IL2Resolver.NotAuthorized.selector));
324+
_l2Resolver.setRecord(_nodeNameHash, _key, _chainIdBytes);
325+
}
326+
327+
function test_SetRecordWhenTheCallerIsNotAuthorizedOnTheParent(
328+
address _parentNodeOwner,
329+
address _caller
330+
) external whenTheNodeHasNoENSRegistryOwner {
331+
vm.assume(_parentNodeOwner != address(0));
332+
vm.assume(_parentNodeOwner != _nameWrapper);
333+
vm.assume(_caller != _parentNodeOwner);
334+
335+
vm.mockCall(
336+
address(_ensRegistry), abi.encodeWithSelector(IENS.owner.selector, _parentNodeNameHash), abi.encode(address(0))
337+
);
338+
vm.expectCall(address(_ensRegistry), abi.encodeWithSelector(IENS.owner.selector, _parentNodeNameHash));
339+
340+
// it reverts
341+
vm.prank(_caller);
342+
vm.expectRevert(abi.encodeWithSelector(IL2Resolver.NotAuthorized.selector));
343+
_l2Resolver.setRecord(_nodeNameHash, _key, _chainIdBytes);
27344
}
28345
}

test/unit/L2Resolver.tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,37 @@ UnitL2Resolver::constructor
44
├── it sets the name wrapper address
55
├── it sets the reverse admin address
66
└── it sets the parent node namehash
7+
8+
UnitL2Resolver::setRecord
9+
├── when the node is the reverse lookup node
10+
│ ├── when the caller is the reverse admin
11+
│ │ ├── it emits the RecordSet event
12+
│ │ └── it sets the record
13+
│ └── when the caller is not the reverse admin
14+
│ └── it reverts
15+
├── when the node has an ENSRegistry owner
16+
│ ├── when the caller is the beneficial owner
17+
│ │ ├── it emits the RecordSet event
18+
│ │ └── it sets the record
19+
│ ├── when the caller is an ENSRegistry approved operator
20+
│ │ ├── it emits the RecordSet event
21+
│ │ └── it sets the record
22+
│ ├── when the caller is a NameWrapper approved operator
23+
│ │ ├── it emits the RecordSet event
24+
│ │ └── it sets the record
25+
│ └── when the caller is neither owner nor approved
26+
│ └── it reverts
27+
└── when the node has no ENSRegistry owner
28+
├── when the caller is the parent owner
29+
│ ├── it emits the RecordSet event
30+
│ └── it sets the record
31+
├── when the caller is an ENSregistry approved operator of the parent
32+
│ ├── it emits the RecordSet event
33+
│ └── it sets the record
34+
├── when the caller is a NameWrapper approved operator of the parent
35+
│ ├── it emits the RecordSet event
36+
│ └── it sets the record
37+
├── when the caller is not an approved operator of the parent
38+
│ └── it reverts
39+
└── when the caller is not authorized on the parent
40+
└── it reverts

0 commit comments

Comments
 (0)