Skip to content

Commit

Permalink
test(RONRegistrarController): unit test for bulkRenew func
Browse files Browse the repository at this point in the history
  • Loading branch information
tringuyenskymavis committed Oct 17, 2024
1 parent 81ea8cf commit bbf5b4d
Show file tree
Hide file tree
Showing 3 changed files with 314 additions and 1 deletion.
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ffi = true

solc = '0.8.21'
extra_output = ["devdoc", "userdoc", "storagelayout"]
evm_version = 'istanbul'
evm_version = 'london'
use_literal_content = true
fs_permissions = [{ access = "read-write", path = "./" }]

Expand Down
216 changes: 216 additions & 0 deletions test/RONRegistrarController/RONRegistrarController.bulkRenew.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { console2, Test } from "forge-std/Test.sol";
import { RNSUnified } from "@rns-contracts/RNSUnified.sol";
import {
RONRegistrarController,
IRONRegistrarController,
INSUnified,
INameChecker,
INSDomainPrice,
INSReverseRegistrar
} from "@rns-contracts/RONRegistrarController.sol";
import { RONTransferHelper } from "@rns-contracts/libraries/transfers/RONTransferHelper.sol";
import { LibString } from "@rns-contracts/libraries/LibString.sol";
import { LibRNSDomain } from "@rns-contracts/libraries/LibRNSDomain.sol";
import { RONRegistrarControllerTest } from "./RONRegistrarController.t.sol";

contract RONRegistrarControllerBulkRenewTest is RONRegistrarControllerTest {
event NameRenewed(string name, uint256 indexed id, uint256 cost, uint64 expires);

function testConcreate_Renew_2names_Check_CorrectFeeCharged() external {
string[] memory names = new string[](2);
names[0] = "tori.ron";
names[1] = "test.ron";

(uint256[] memory ids, string[] memory sortedNames) = _sortNames(names);
uint64[] memory expires = new uint64[](ids.length);
uint64 duration = 30 days;
for (uint256 i; i < ids.length; ++i) {
console2.log("id", ids[i]);
console2.log("name", sortedNames[i]);
expires[i] = _rnsUnified.getRecord(ids[i]).mut.expiry + duration;
}

uint256[] memory fees = new uint256[](2);
fees[0] = _calFee(names[0], duration);
fees[1] = _calFee(names[1], duration);

uint256 totalFee = fees[0] + fees[1];

uint256 sendValue = 10 ether;
uint256 balanceBefore = address(_caller).balance;

uint64[] memory durations = new uint64[](2);
durations[0] = duration;
durations[1] = duration;
_expectEmit(sortedNames, ids, fees, expires);
vm.prank(_caller);
_controller.bulkRenew{ value: sendValue }(sortedNames, durations);
assertEq(address(_caller).balance, balanceBefore - totalFee);

durations[0] = duration;
durations[1] = duration;
vm.prank(_caller);
_controller.bulkRenew{ value: sendValue }(sortedNames, durations);
}

function testConcreate_bulkRenew_TheSameName_CorrectFeeCharged() external {
string[] memory names = new string[](2);
names[0] = "tori.vip.ron";
names[1] = "tori.vip.ron";

uint64 duration = 30 days;
uint64[] memory durations = new uint64[](2);
durations[0] = duration;
durations[1] = duration;
uint256 balanceBefore = address(_caller).balance;

uint256 fee = _calFee(names[0], duration) * 2;

vm.prank(_caller);
_controller.bulkRenew{ value: 10 ether }(names, durations);

assertEq(address(_caller).balance, balanceBefore - fee);
assertEq(_treasury.balance, fee);
}

function testRevert_bulkRenew_InsufficientValue() external {
string[] memory names = new string[](2);
names[0] = "test.ron";
names[1] = "tori.ron";

uint64 duration = 30 days;
uint64[] memory durations = new uint64[](2);
durations[0] = duration;
durations[1] = duration;

uint256 name0Fee = _calFee(names[0], duration);
uint256 name1Fee = _calFee(names[1], duration);

vm.prank(_caller);
vm.expectRevert(IRONRegistrarController.InsufficientValue.selector);
_controller.bulkRenew{ value: name0Fee + name1Fee - 1 }(names, durations);

// Call success
_controller.bulkRenew{ value: name0Fee + name1Fee }(names, durations);
}

function testRevert_bulkRenew_ExpiryNotLargerThanOldOne() external {
string[] memory names = new string[](1);
names[0] = "test.ron";

uint64[] memory durations = new uint64[](1);
durations[0] = 0;

vm.prank(_caller);
vm.expectRevert(INSUnified.ExpiryTimeMustBeLargerThanTheOldOne.selector);
_controller.bulkRenew{ value: 10 ether }(names, durations);
}

function testBenchMark_bulkRenew(uint8 times) external {
vm.pauseGasMetering();
vm.assume(times > 0);
string[] memory names = new string[](times);
uint64[] memory durations = new uint64[](times);
uint256 totalFee;
for (uint256 i; i < times; ++i) {
names[i] = string.concat("test", vm.toString(i), ".ron");
durations[i] = 30 days;
totalFee += _calFee(names[i], durations[i]);
}
vm.deal(_caller, totalFee + 10 ether);
(, string[] memory sortedNames) = _sortNames(names);
vm.resumeGasMetering();
vm.prank(_caller);
_controller.bulkRenew{ value: totalFee + 10 ether }(sortedNames, durations);

assertEq(address(_caller).balance, 10 ether);
assertEq(_treasury.balance, totalFee);
}

function testRevert_bulkRenew_InvalidArrayLength() external {
string[] memory names = new string[](2);
names[0] = "test.ron";
names[1] = "tori.ron";

uint64[] memory durations = new uint64[](1);
durations[0] = 30 days;

vm.prank(_caller);
vm.expectRevert(IRONRegistrarController.InvalidArrayLength.selector);
_controller.bulkRenew{ value: 10 ether }(names, durations);

names = new string[](0);
durations = new uint64[](0);
vm.expectRevert(IRONRegistrarController.InvalidArrayLength.selector);
_controller.bulkRenew{ value: 10 ether }(names, durations);
}

function testConcreate_DuplicateNames_With_TheSameDuration() external {
string[] memory names = new string[](2);
names[0] = "test.ron";
names[1] = "test.ron";

uint64[] memory durations = new uint64[](2);
durations[0] = 30 days;
durations[1] = 30 days;

vm.prank(_caller);
// vm.expectRevert(IRONRegistrarController.InvalidArrayLength.selector);
_controller.bulkRenew{ value: 10 ether }(names, durations);
}

function testConcreate_DuplicateNames_With_DifferentDuration() external {
string[] memory names = new string[](2);
names[0] = "test.ron";
names[1] = "test.ron";

uint64[] memory durations = new uint64[](2);
durations[0] = 30 days;
durations[1] = 10 days;

vm.prank(_caller);
// vm.expectRevert(IRONRegistrarController.InvalidArrayLength.selector);
_controller.bulkRenew{ value: 10 ether }(names, durations);
}

function _calFee(string memory name, uint64 duration) internal returns (uint256) {
(, uint256 ronPrice) = _controller.rentPrice(name, duration);
return ronPrice;
}

function _sortNames(string[] memory names) internal returns (uint256[] memory, string[] memory) {
uint256[] memory ids = new uint256[](names.length);
for (uint256 i = 0; i < names.length; i++) {
ids[i] = _controller.computeId(names[i]);
}

for (uint256 i = 0; i < names.length; i++) {
for (uint256 j = i + 1; j < names.length; j++) {
if (ids[i] > ids[j]) {
uint256 tempId = ids[i];
ids[i] = ids[j];
ids[j] = tempId;

string memory tempName = names[i];
names[i] = names[j];
names[j] = tempName;
}
}
}
return (ids, names);
}

function _expectEmit(string[] memory names, uint256[] memory ids, uint256[] memory fees, uint64[] memory expires)
internal
{
for (uint256 i; i < names.length; ++i) {
vm.expectEmit(false, true, false, true);
emit NameRenewed(names[i], ids[i], fees[i], expires[i]);
}
}
}
97 changes: 97 additions & 0 deletions test/RONRegistrarController/RONRegistrarController.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { console2, Test } from "forge-std/Test.sol";
import { RNSUnified } from "@rns-contracts/RNSUnified.sol";
import {
RONRegistrarController,
INSUnified,
INameChecker,
INSDomainPrice,
INSReverseRegistrar
} from "@rns-contracts/RONRegistrarController.sol";
import { RONTransferHelper } from "@rns-contracts/libraries/transfers/RONTransferHelper.sol";
import { LibString } from "@rns-contracts/libraries/LibString.sol";
import { LibRNSDomain } from "@rns-contracts/libraries/LibRNSDomain.sol";
import { RNSUnifiedDeploy } from "script/contracts/RNSUnifiedDeploy.s.sol";

contract RONRegistrarControllerTest is Test {
using LibString for string;
using LibRNSDomain for string;

address internal _caller;
address internal _admin;
address internal _pauser;
address internal _proxyAdmin;
address payable internal _treasury;
uint256 internal _maxCommitmentAge;
uint256 internal _minCommitmentAge;
uint256 internal _minRegistrationDuration;
INSUnified internal _rnsUnified;
INameChecker internal _nameChecker;
INSDomainPrice internal _priceOracle;
INSReverseRegistrar internal _reverseRegistrar;

RONRegistrarController internal _controller;

function setUp() external {
vm.warp(block.timestamp + 10 days);
_caller = makeAddr("caller");
_admin = makeAddr("admin");
_pauser = makeAddr("pauser");
_proxyAdmin = makeAddr("proxyAdmin");
_treasury = payable(makeAddr("treasury"));
_maxCommitmentAge = 1 days;
_minCommitmentAge = 10 seconds;
_minRegistrationDuration = 1 days;
_rnsUnified = INSUnified(address(new RNSUnifiedDeploy().run()));
_nameChecker = INameChecker(makeAddr("nameChecker"));
_priceOracle = INSDomainPrice(address(new PriceOracleMock()));
_reverseRegistrar = INSReverseRegistrar(makeAddr("reverseRegistrar"));
vm.deal(_caller, 100 ether);

address logic = address(new RONRegistrarController());
_controller = RONRegistrarController(
address(
new TransparentUpgradeableProxy(
logic,
_proxyAdmin,
abi.encodeCall(
RONRegistrarController.initialize,
(
_admin,
_pauser,
_treasury,
_maxCommitmentAge,
_minCommitmentAge,
_minRegistrationDuration,
_rnsUnified,
_nameChecker,
_priceOracle,
_reverseRegistrar
)
)
)
)
);

RNSUnified _rns = RNSUnified(address(_rnsUnified));
address admin = _rns.getRoleMember(_rns.DEFAULT_ADMIN_ROLE(), 0);
bytes32 controllerRole = _rns.CONTROLLER_ROLE();
vm.prank(admin);
_rns.grantRole(controllerRole, address(_controller));
}
}

contract PriceOracleMock {
function getRenewalFee(string calldata label, uint256 duration)
external
view
returns (INSDomainPrice.UnitPrice memory basePrice, INSDomainPrice.UnitPrice memory tax)
{
basePrice = INSDomainPrice.UnitPrice({ usd: 1.5 ether, ron: 1 ether });
tax = INSDomainPrice.UnitPrice({ usd: 0.15 ether, ron: 0.1 ether });
}
}

0 comments on commit bbf5b4d

Please sign in to comment.