@bananapus/router-terminal-v6 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,333 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.26;
3
+
4
+ import "forge-std/Test.sol";
5
+
6
+ import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
7
+ import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
8
+ import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
9
+ import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
10
+ import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
11
+ import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
12
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
13
+ import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
14
+ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
15
+ import {IPermit2} from "@uniswap/permit2/src/interfaces/IPermit2.sol";
16
+
17
+ import {JBRouterTerminalRegistry} from "../src/JBRouterTerminalRegistry.sol";
18
+ import {IJBRouterTerminalRegistry} from "../src/interfaces/IJBRouterTerminalRegistry.sol";
19
+
20
+ contract RouterTerminalRegistryTest is Test {
21
+ JBRouterTerminalRegistry registry;
22
+
23
+ // Mocked dependencies.
24
+ IJBPermissions permissions = IJBPermissions(makeAddr("permissions"));
25
+ IJBProjects projects = IJBProjects(makeAddr("projects"));
26
+ IPermit2 permit2 = IPermit2(makeAddr("permit2"));
27
+ address owner = makeAddr("owner");
28
+ address trustedForwarder = makeAddr("trustedForwarder");
29
+
30
+ // Mocked terminals.
31
+ IJBTerminal terminalA = IJBTerminal(makeAddr("terminalA"));
32
+ IJBTerminal terminalB = IJBTerminal(makeAddr("terminalB"));
33
+
34
+ // Test constants.
35
+ uint256 projectId = 1;
36
+ address projectOwner = makeAddr("projectOwner");
37
+
38
+ function setUp() public {
39
+ registry = new JBRouterTerminalRegistry(permissions, projects, permit2, owner, trustedForwarder);
40
+ }
41
+
42
+ // ──────────────────────────────────────────────────────────────────────
43
+ // Constructor / immutables
44
+ // ──────────────────────────────────────────────────────────────────────
45
+
46
+ function test_constructor() public view {
47
+ assertEq(address(registry.PROJECTS()), address(projects));
48
+ assertEq(address(registry.PERMIT2()), address(permit2));
49
+ assertEq(address(registry.defaultTerminal()), address(0));
50
+ }
51
+
52
+ // ──────────────────────────────────────────────────────────────────────
53
+ // allowTerminal / disallowTerminal
54
+ // ──────────────────────────────────────────────────────────────────────
55
+
56
+ function test_allowTerminal() public {
57
+ vm.prank(owner);
58
+ registry.allowTerminal(terminalA);
59
+
60
+ assertTrue(registry.isTerminalAllowed(terminalA));
61
+ }
62
+
63
+ function test_allowTerminal_revertsIfNotOwner() public {
64
+ vm.expectRevert();
65
+ registry.allowTerminal(terminalA);
66
+ }
67
+
68
+ function test_disallowTerminal() public {
69
+ vm.startPrank(owner);
70
+ registry.allowTerminal(terminalA);
71
+ registry.disallowTerminal(terminalA);
72
+ vm.stopPrank();
73
+
74
+ assertFalse(registry.isTerminalAllowed(terminalA));
75
+ }
76
+
77
+ function test_disallowTerminal_clearsDefault() public {
78
+ vm.startPrank(owner);
79
+ registry.setDefaultTerminal(terminalA);
80
+ registry.disallowTerminal(terminalA);
81
+ vm.stopPrank();
82
+
83
+ assertEq(address(registry.defaultTerminal()), address(0));
84
+ }
85
+
86
+ // ──────────────────────────────────────────────────────────────────────
87
+ // setDefaultTerminal
88
+ // ──────────────────────────────────────────────────────────────────────
89
+
90
+ function test_setDefaultTerminal() public {
91
+ vm.prank(owner);
92
+ registry.setDefaultTerminal(terminalA);
93
+
94
+ assertEq(address(registry.defaultTerminal()), address(terminalA));
95
+ assertTrue(registry.isTerminalAllowed(terminalA));
96
+ }
97
+
98
+ function test_setDefaultTerminal_revertsIfNotOwner() public {
99
+ vm.expectRevert();
100
+ registry.setDefaultTerminal(terminalA);
101
+ }
102
+
103
+ // ──────────────────────────────────────────────────────────────────────
104
+ // terminalOf
105
+ // ──────────────────────────────────────────────────────────────────────
106
+
107
+ function test_terminalOf_fallsBackToDefault() public {
108
+ vm.prank(owner);
109
+ registry.setDefaultTerminal(terminalA);
110
+
111
+ assertEq(address(registry.terminalOf(projectId)), address(terminalA));
112
+ }
113
+
114
+ function test_terminalOf_returnsProjectSpecific() public {
115
+ vm.prank(owner);
116
+ registry.setDefaultTerminal(terminalA);
117
+
118
+ // Allow terminalB and set it for the project.
119
+ vm.prank(owner);
120
+ registry.allowTerminal(terminalB);
121
+
122
+ // Mock the project owner.
123
+ vm.mockCall(address(projects), abi.encodeCall(IERC721.ownerOf, (projectId)), abi.encode(projectOwner));
124
+ // Mock the permission check.
125
+ vm.mockCall(
126
+ address(permissions),
127
+ abi.encodeWithSignature(
128
+ "hasPermission(address,address,uint256,uint256,bool,bool)",
129
+ projectOwner,
130
+ projectOwner,
131
+ projectId,
132
+ JBPermissionIds.SET_ROUTER_TERMINAL,
133
+ true,
134
+ true
135
+ ),
136
+ abi.encode(true)
137
+ );
138
+
139
+ vm.prank(projectOwner);
140
+ registry.setTerminalFor(projectId, terminalB);
141
+
142
+ assertEq(address(registry.terminalOf(projectId)), address(terminalB));
143
+ }
144
+
145
+ // ──────────────────────────────────────────────────────────────────────
146
+ // setTerminalFor
147
+ // ──────────────────────────────────────────────────────────────────────
148
+
149
+ function test_setTerminalFor_revertsIfNotAllowed() public {
150
+ // Mock the project owner.
151
+ vm.mockCall(address(projects), abi.encodeCall(IERC721.ownerOf, (projectId)), abi.encode(projectOwner));
152
+ vm.mockCall(
153
+ address(permissions),
154
+ abi.encodeWithSignature(
155
+ "hasPermission(address,address,uint256,uint256,bool,bool)",
156
+ projectOwner,
157
+ projectOwner,
158
+ projectId,
159
+ JBPermissionIds.SET_ROUTER_TERMINAL,
160
+ true,
161
+ true
162
+ ),
163
+ abi.encode(true)
164
+ );
165
+
166
+ vm.prank(projectOwner);
167
+ vm.expectRevert(
168
+ abi.encodeWithSelector(
169
+ JBRouterTerminalRegistry.JBRouterTerminalRegistry_TerminalNotAllowed.selector, terminalA
170
+ )
171
+ );
172
+ registry.setTerminalFor(projectId, terminalA);
173
+ }
174
+
175
+ function test_setTerminalFor_revertsIfLocked() public {
176
+ // Set up: allow terminal, set it, lock it.
177
+ vm.prank(owner);
178
+ registry.allowTerminal(terminalA);
179
+
180
+ vm.mockCall(address(projects), abi.encodeCall(IERC721.ownerOf, (projectId)), abi.encode(projectOwner));
181
+ vm.mockCall(
182
+ address(permissions),
183
+ abi.encodeWithSignature(
184
+ "hasPermission(address,address,uint256,uint256,bool,bool)",
185
+ projectOwner,
186
+ projectOwner,
187
+ projectId,
188
+ JBPermissionIds.SET_ROUTER_TERMINAL,
189
+ true,
190
+ true
191
+ ),
192
+ abi.encode(true)
193
+ );
194
+
195
+ vm.prank(projectOwner);
196
+ registry.setTerminalFor(projectId, terminalA);
197
+
198
+ vm.prank(projectOwner);
199
+ registry.lockTerminalFor(projectId);
200
+
201
+ // Try to change.
202
+ vm.prank(projectOwner);
203
+ vm.expectRevert(
204
+ abi.encodeWithSelector(JBRouterTerminalRegistry.JBRouterTerminalRegistry_TerminalLocked.selector, projectId)
205
+ );
206
+ registry.setTerminalFor(projectId, terminalA);
207
+ }
208
+
209
+ // ──────────────────────────────────────────────────────────────────────
210
+ // lockTerminalFor
211
+ // ──────────────────────────────────────────────────────────────────────
212
+
213
+ function test_lockTerminalFor_snapshotsDefault() public {
214
+ // Set up default, no project-specific terminal.
215
+ vm.prank(owner);
216
+ registry.setDefaultTerminal(terminalA);
217
+
218
+ vm.mockCall(address(projects), abi.encodeCall(IERC721.ownerOf, (projectId)), abi.encode(projectOwner));
219
+ vm.mockCall(
220
+ address(permissions),
221
+ abi.encodeWithSignature(
222
+ "hasPermission(address,address,uint256,uint256,bool,bool)",
223
+ projectOwner,
224
+ projectOwner,
225
+ projectId,
226
+ JBPermissionIds.SET_ROUTER_TERMINAL,
227
+ true,
228
+ true
229
+ ),
230
+ abi.encode(true)
231
+ );
232
+
233
+ vm.prank(projectOwner);
234
+ registry.lockTerminalFor(projectId);
235
+
236
+ assertTrue(registry.hasLockedTerminal(projectId));
237
+ // Should have snapshotted the default as the project's terminal.
238
+ assertEq(address(registry.terminalOf(projectId)), address(terminalA));
239
+ }
240
+
241
+ function test_lockTerminalFor_revertsIfNoTerminal() public {
242
+ vm.mockCall(address(projects), abi.encodeCall(IERC721.ownerOf, (projectId)), abi.encode(projectOwner));
243
+ vm.mockCall(
244
+ address(permissions),
245
+ abi.encodeWithSignature(
246
+ "hasPermission(address,address,uint256,uint256,bool,bool)",
247
+ projectOwner,
248
+ projectOwner,
249
+ projectId,
250
+ JBPermissionIds.SET_ROUTER_TERMINAL,
251
+ true,
252
+ true
253
+ ),
254
+ abi.encode(true)
255
+ );
256
+
257
+ vm.prank(projectOwner);
258
+ vm.expectRevert(
259
+ abi.encodeWithSelector(
260
+ JBRouterTerminalRegistry.JBRouterTerminalRegistry_TerminalNotSet.selector, projectId
261
+ )
262
+ );
263
+ registry.lockTerminalFor(projectId);
264
+ }
265
+
266
+ // ──────────────────────────────────────────────────────────────────────
267
+ // supportsInterface
268
+ // ──────────────────────────────────────────────────────────────────────
269
+
270
+ function test_supportsInterface() public view {
271
+ assertTrue(registry.supportsInterface(type(IJBRouterTerminalRegistry).interfaceId));
272
+ assertTrue(registry.supportsInterface(type(IJBTerminal).interfaceId));
273
+ assertTrue(registry.supportsInterface(type(IERC165).interfaceId));
274
+ assertFalse(registry.supportsInterface(bytes4(0xdeadbeef)));
275
+ }
276
+
277
+ // ──────────────────────────────────────────────────────────────────────
278
+ // pay (forwarding)
279
+ // ──────────────────────────────────────────────────────────────────────
280
+
281
+ function test_pay_forwardsToDefault() public {
282
+ vm.prank(owner);
283
+ registry.setDefaultTerminal(terminalA);
284
+
285
+ // Mock the terminal's pay to return 100.
286
+ vm.mockCall(
287
+ address(terminalA),
288
+ abi.encodeWithSelector(IJBTerminal.pay.selector),
289
+ abi.encode(uint256(100))
290
+ );
291
+
292
+ // Send native tokens.
293
+ vm.deal(address(this), 1 ether);
294
+ uint256 returned = registry.pay{value: 1 ether}({
295
+ projectId: projectId,
296
+ token: JBConstants.NATIVE_TOKEN,
297
+ amount: 1 ether,
298
+ beneficiary: address(this),
299
+ minReturnedTokens: 0,
300
+ memo: "",
301
+ metadata: ""
302
+ });
303
+
304
+ assertEq(returned, 100);
305
+ }
306
+
307
+ // ──────────────────────────────────────────────────────────────────────
308
+ // addToBalanceOf (forwarding)
309
+ // ──────────────────────────────────────────────────────────────────────
310
+
311
+ function test_addToBalanceOf_forwardsToDefault() public {
312
+ vm.prank(owner);
313
+ registry.setDefaultTerminal(terminalA);
314
+
315
+ // Mock the terminal's addToBalanceOf.
316
+ vm.mockCall(
317
+ address(terminalA),
318
+ abi.encodeWithSelector(IJBTerminal.addToBalanceOf.selector),
319
+ abi.encode()
320
+ );
321
+
322
+ // Send native tokens.
323
+ vm.deal(address(this), 1 ether);
324
+ registry.addToBalanceOf{value: 1 ether}({
325
+ projectId: projectId,
326
+ token: JBConstants.NATIVE_TOKEN,
327
+ amount: 1 ether,
328
+ shouldReturnHeldFees: false,
329
+ memo: "",
330
+ metadata: ""
331
+ });
332
+ }
333
+ }