Skip to content

Commit bbf5b4d

Browse files
test(RONRegistrarController): unit test for bulkRenew func
1 parent 81ea8cf commit bbf5b4d

File tree

3 files changed

+314
-1
lines changed

3 files changed

+314
-1
lines changed

foundry.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ffi = true
77

88
solc = '0.8.21'
99
extra_output = ["devdoc", "userdoc", "storagelayout"]
10-
evm_version = 'istanbul'
10+
evm_version = 'london'
1111
use_literal_content = true
1212
fs_permissions = [{ access = "read-write", path = "./" }]
1313

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.19;
3+
4+
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
5+
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
6+
import { console2, Test } from "forge-std/Test.sol";
7+
import { RNSUnified } from "@rns-contracts/RNSUnified.sol";
8+
import {
9+
RONRegistrarController,
10+
IRONRegistrarController,
11+
INSUnified,
12+
INameChecker,
13+
INSDomainPrice,
14+
INSReverseRegistrar
15+
} from "@rns-contracts/RONRegistrarController.sol";
16+
import { RONTransferHelper } from "@rns-contracts/libraries/transfers/RONTransferHelper.sol";
17+
import { LibString } from "@rns-contracts/libraries/LibString.sol";
18+
import { LibRNSDomain } from "@rns-contracts/libraries/LibRNSDomain.sol";
19+
import { RONRegistrarControllerTest } from "./RONRegistrarController.t.sol";
20+
21+
contract RONRegistrarControllerBulkRenewTest is RONRegistrarControllerTest {
22+
event NameRenewed(string name, uint256 indexed id, uint256 cost, uint64 expires);
23+
24+
function testConcreate_Renew_2names_Check_CorrectFeeCharged() external {
25+
string[] memory names = new string[](2);
26+
names[0] = "tori.ron";
27+
names[1] = "test.ron";
28+
29+
(uint256[] memory ids, string[] memory sortedNames) = _sortNames(names);
30+
uint64[] memory expires = new uint64[](ids.length);
31+
uint64 duration = 30 days;
32+
for (uint256 i; i < ids.length; ++i) {
33+
console2.log("id", ids[i]);
34+
console2.log("name", sortedNames[i]);
35+
expires[i] = _rnsUnified.getRecord(ids[i]).mut.expiry + duration;
36+
}
37+
38+
uint256[] memory fees = new uint256[](2);
39+
fees[0] = _calFee(names[0], duration);
40+
fees[1] = _calFee(names[1], duration);
41+
42+
uint256 totalFee = fees[0] + fees[1];
43+
44+
uint256 sendValue = 10 ether;
45+
uint256 balanceBefore = address(_caller).balance;
46+
47+
uint64[] memory durations = new uint64[](2);
48+
durations[0] = duration;
49+
durations[1] = duration;
50+
_expectEmit(sortedNames, ids, fees, expires);
51+
vm.prank(_caller);
52+
_controller.bulkRenew{ value: sendValue }(sortedNames, durations);
53+
assertEq(address(_caller).balance, balanceBefore - totalFee);
54+
55+
durations[0] = duration;
56+
durations[1] = duration;
57+
vm.prank(_caller);
58+
_controller.bulkRenew{ value: sendValue }(sortedNames, durations);
59+
}
60+
61+
function testConcreate_bulkRenew_TheSameName_CorrectFeeCharged() external {
62+
string[] memory names = new string[](2);
63+
names[0] = "tori.vip.ron";
64+
names[1] = "tori.vip.ron";
65+
66+
uint64 duration = 30 days;
67+
uint64[] memory durations = new uint64[](2);
68+
durations[0] = duration;
69+
durations[1] = duration;
70+
uint256 balanceBefore = address(_caller).balance;
71+
72+
uint256 fee = _calFee(names[0], duration) * 2;
73+
74+
vm.prank(_caller);
75+
_controller.bulkRenew{ value: 10 ether }(names, durations);
76+
77+
assertEq(address(_caller).balance, balanceBefore - fee);
78+
assertEq(_treasury.balance, fee);
79+
}
80+
81+
function testRevert_bulkRenew_InsufficientValue() external {
82+
string[] memory names = new string[](2);
83+
names[0] = "test.ron";
84+
names[1] = "tori.ron";
85+
86+
uint64 duration = 30 days;
87+
uint64[] memory durations = new uint64[](2);
88+
durations[0] = duration;
89+
durations[1] = duration;
90+
91+
uint256 name0Fee = _calFee(names[0], duration);
92+
uint256 name1Fee = _calFee(names[1], duration);
93+
94+
vm.prank(_caller);
95+
vm.expectRevert(IRONRegistrarController.InsufficientValue.selector);
96+
_controller.bulkRenew{ value: name0Fee + name1Fee - 1 }(names, durations);
97+
98+
// Call success
99+
_controller.bulkRenew{ value: name0Fee + name1Fee }(names, durations);
100+
}
101+
102+
function testRevert_bulkRenew_ExpiryNotLargerThanOldOne() external {
103+
string[] memory names = new string[](1);
104+
names[0] = "test.ron";
105+
106+
uint64[] memory durations = new uint64[](1);
107+
durations[0] = 0;
108+
109+
vm.prank(_caller);
110+
vm.expectRevert(INSUnified.ExpiryTimeMustBeLargerThanTheOldOne.selector);
111+
_controller.bulkRenew{ value: 10 ether }(names, durations);
112+
}
113+
114+
function testBenchMark_bulkRenew(uint8 times) external {
115+
vm.pauseGasMetering();
116+
vm.assume(times > 0);
117+
string[] memory names = new string[](times);
118+
uint64[] memory durations = new uint64[](times);
119+
uint256 totalFee;
120+
for (uint256 i; i < times; ++i) {
121+
names[i] = string.concat("test", vm.toString(i), ".ron");
122+
durations[i] = 30 days;
123+
totalFee += _calFee(names[i], durations[i]);
124+
}
125+
vm.deal(_caller, totalFee + 10 ether);
126+
(, string[] memory sortedNames) = _sortNames(names);
127+
vm.resumeGasMetering();
128+
vm.prank(_caller);
129+
_controller.bulkRenew{ value: totalFee + 10 ether }(sortedNames, durations);
130+
131+
assertEq(address(_caller).balance, 10 ether);
132+
assertEq(_treasury.balance, totalFee);
133+
}
134+
135+
function testRevert_bulkRenew_InvalidArrayLength() external {
136+
string[] memory names = new string[](2);
137+
names[0] = "test.ron";
138+
names[1] = "tori.ron";
139+
140+
uint64[] memory durations = new uint64[](1);
141+
durations[0] = 30 days;
142+
143+
vm.prank(_caller);
144+
vm.expectRevert(IRONRegistrarController.InvalidArrayLength.selector);
145+
_controller.bulkRenew{ value: 10 ether }(names, durations);
146+
147+
names = new string[](0);
148+
durations = new uint64[](0);
149+
vm.expectRevert(IRONRegistrarController.InvalidArrayLength.selector);
150+
_controller.bulkRenew{ value: 10 ether }(names, durations);
151+
}
152+
153+
function testConcreate_DuplicateNames_With_TheSameDuration() external {
154+
string[] memory names = new string[](2);
155+
names[0] = "test.ron";
156+
names[1] = "test.ron";
157+
158+
uint64[] memory durations = new uint64[](2);
159+
durations[0] = 30 days;
160+
durations[1] = 30 days;
161+
162+
vm.prank(_caller);
163+
// vm.expectRevert(IRONRegistrarController.InvalidArrayLength.selector);
164+
_controller.bulkRenew{ value: 10 ether }(names, durations);
165+
}
166+
167+
function testConcreate_DuplicateNames_With_DifferentDuration() external {
168+
string[] memory names = new string[](2);
169+
names[0] = "test.ron";
170+
names[1] = "test.ron";
171+
172+
uint64[] memory durations = new uint64[](2);
173+
durations[0] = 30 days;
174+
durations[1] = 10 days;
175+
176+
vm.prank(_caller);
177+
// vm.expectRevert(IRONRegistrarController.InvalidArrayLength.selector);
178+
_controller.bulkRenew{ value: 10 ether }(names, durations);
179+
}
180+
181+
function _calFee(string memory name, uint64 duration) internal returns (uint256) {
182+
(, uint256 ronPrice) = _controller.rentPrice(name, duration);
183+
return ronPrice;
184+
}
185+
186+
function _sortNames(string[] memory names) internal returns (uint256[] memory, string[] memory) {
187+
uint256[] memory ids = new uint256[](names.length);
188+
for (uint256 i = 0; i < names.length; i++) {
189+
ids[i] = _controller.computeId(names[i]);
190+
}
191+
192+
for (uint256 i = 0; i < names.length; i++) {
193+
for (uint256 j = i + 1; j < names.length; j++) {
194+
if (ids[i] > ids[j]) {
195+
uint256 tempId = ids[i];
196+
ids[i] = ids[j];
197+
ids[j] = tempId;
198+
199+
string memory tempName = names[i];
200+
names[i] = names[j];
201+
names[j] = tempName;
202+
}
203+
}
204+
}
205+
return (ids, names);
206+
}
207+
208+
function _expectEmit(string[] memory names, uint256[] memory ids, uint256[] memory fees, uint64[] memory expires)
209+
internal
210+
{
211+
for (uint256 i; i < names.length; ++i) {
212+
vm.expectEmit(false, true, false, true);
213+
emit NameRenewed(names[i], ids[i], fees[i], expires[i]);
214+
}
215+
}
216+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.19;
3+
4+
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
5+
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
6+
import { console2, Test } from "forge-std/Test.sol";
7+
import { RNSUnified } from "@rns-contracts/RNSUnified.sol";
8+
import {
9+
RONRegistrarController,
10+
INSUnified,
11+
INameChecker,
12+
INSDomainPrice,
13+
INSReverseRegistrar
14+
} from "@rns-contracts/RONRegistrarController.sol";
15+
import { RONTransferHelper } from "@rns-contracts/libraries/transfers/RONTransferHelper.sol";
16+
import { LibString } from "@rns-contracts/libraries/LibString.sol";
17+
import { LibRNSDomain } from "@rns-contracts/libraries/LibRNSDomain.sol";
18+
import { RNSUnifiedDeploy } from "script/contracts/RNSUnifiedDeploy.s.sol";
19+
20+
contract RONRegistrarControllerTest is Test {
21+
using LibString for string;
22+
using LibRNSDomain for string;
23+
24+
address internal _caller;
25+
address internal _admin;
26+
address internal _pauser;
27+
address internal _proxyAdmin;
28+
address payable internal _treasury;
29+
uint256 internal _maxCommitmentAge;
30+
uint256 internal _minCommitmentAge;
31+
uint256 internal _minRegistrationDuration;
32+
INSUnified internal _rnsUnified;
33+
INameChecker internal _nameChecker;
34+
INSDomainPrice internal _priceOracle;
35+
INSReverseRegistrar internal _reverseRegistrar;
36+
37+
RONRegistrarController internal _controller;
38+
39+
function setUp() external {
40+
vm.warp(block.timestamp + 10 days);
41+
_caller = makeAddr("caller");
42+
_admin = makeAddr("admin");
43+
_pauser = makeAddr("pauser");
44+
_proxyAdmin = makeAddr("proxyAdmin");
45+
_treasury = payable(makeAddr("treasury"));
46+
_maxCommitmentAge = 1 days;
47+
_minCommitmentAge = 10 seconds;
48+
_minRegistrationDuration = 1 days;
49+
_rnsUnified = INSUnified(address(new RNSUnifiedDeploy().run()));
50+
_nameChecker = INameChecker(makeAddr("nameChecker"));
51+
_priceOracle = INSDomainPrice(address(new PriceOracleMock()));
52+
_reverseRegistrar = INSReverseRegistrar(makeAddr("reverseRegistrar"));
53+
vm.deal(_caller, 100 ether);
54+
55+
address logic = address(new RONRegistrarController());
56+
_controller = RONRegistrarController(
57+
address(
58+
new TransparentUpgradeableProxy(
59+
logic,
60+
_proxyAdmin,
61+
abi.encodeCall(
62+
RONRegistrarController.initialize,
63+
(
64+
_admin,
65+
_pauser,
66+
_treasury,
67+
_maxCommitmentAge,
68+
_minCommitmentAge,
69+
_minRegistrationDuration,
70+
_rnsUnified,
71+
_nameChecker,
72+
_priceOracle,
73+
_reverseRegistrar
74+
)
75+
)
76+
)
77+
)
78+
);
79+
80+
RNSUnified _rns = RNSUnified(address(_rnsUnified));
81+
address admin = _rns.getRoleMember(_rns.DEFAULT_ADMIN_ROLE(), 0);
82+
bytes32 controllerRole = _rns.CONTROLLER_ROLE();
83+
vm.prank(admin);
84+
_rns.grantRole(controllerRole, address(_controller));
85+
}
86+
}
87+
88+
contract PriceOracleMock {
89+
function getRenewalFee(string calldata label, uint256 duration)
90+
external
91+
view
92+
returns (INSDomainPrice.UnitPrice memory basePrice, INSDomainPrice.UnitPrice memory tax)
93+
{
94+
basePrice = INSDomainPrice.UnitPrice({ usd: 1.5 ether, ron: 1 ether });
95+
tax = INSDomainPrice.UnitPrice({ usd: 0.15 ether, ron: 0.1 ether });
96+
}
97+
}

0 commit comments

Comments
 (0)