Skip to content

Commit

Permalink
feat(script): implement add-v0.3.4-rns-unified-migration-script (#185)
Browse files Browse the repository at this point in the history
  • Loading branch information
TuDo1403 authored Mar 25, 2024
2 parents 0b32c2e + a374601 commit b413651
Show file tree
Hide file tree
Showing 11 changed files with 513 additions and 6 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ docs/
node_modules/
yarn-error.log
.yarn
.yarnrc.yml
.yarnrc.yml
script/data/*
8 changes: 5 additions & 3 deletions config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ loadConfig() {
ERC721_BATCH_TRANSFER=0x2368dfed532842db89b470fde9fd584d48d4f644

if [ "$MODE" == "broadcast" ]; then
PK=$TESTNET_PK
PK=$MAINNET_PK
fi
else
RPC=$TESTNET_URL
Expand All @@ -37,18 +37,20 @@ loadConfig() {
ERC721_BATCH_TRANSFER=0x2e889348bd37f192063bfec8ff39bd3635949e20

if [ "$MODE" == "broadcast" ]; then
PK=$MAINNET_PK
PK=$TESTNET_PK
fi
fi

if [ "$MODE" == "broadcast" ]; then
CURRENT_NONCE=$(cast nonce --rpc-url $RPC $FROM)
CURRENT_GAS_PRICE=$(cast gas-price --rpc-url $RPC)

if [[ "$PK" == op://* ]]; then
PK=$(op read "$PK")
fi
fi

CURRENT_NONCE=$(cast nonce --rpc-url $RPC $FROM)
echo "Current nonce: $CURRENT_NONCE"
}

# Function to load address from deployment file
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { StdStyle } from "forge-std/StdStyle.sol";
import { IMulticall3 } from "forge-std/interfaces/IMulticall3.sol";
import { LibString } from "solady/utils/LibString.sol";
import { DefaultNetwork } from "foundry-deployment-kit/utils/DefaultNetwork.sol";
import { DefaultContract } from "foundry-deployment-kit/utils/DefaultContract.sol";
import { Contract } from "../utils/Contract.sol";
import { INSDomainPrice, RNSDomainPrice } from "@rns-contracts/RNSDomainPrice.sol";
import "./20240215_Migration.s.sol";

contract Migration__01_UpgradeRNSDomainPriceAndOverrideTierForCommunityNames_RNSDomainPrice is Migration__20240215 {
using StdStyle for *;
using LibString for *;

RNSDomainPrice internal _domainPrice;
IMulticall3 internal _multicall;
bytes32[] internal _lbHashes;

function run() external {
_domainPrice = RNSDomainPrice(_upgradeProxy(Contract.RNSDomainPrice.key()));
}

function _postCheck() internal override logFn("_postChecking ...") {
_multicall = IMulticall3(loadContract(DefaultContract.Multicall3.key()));

(_labels, _tiers) = _parseData(DATA_PATH);

_lbHashes = toLabelHashes(_labels);

uint256 batchSize = 100;
uint256 totalElements = _lbHashes.length;
uint256 totalBatches = (totalElements + batchSize - 1) / batchSize;

address overrider = _domainPrice.getRoleMember(_domainPrice.OVERRIDER_ROLE(), 0);
console.log("Overrider".yellow(), overrider);

for (uint256 i; i < totalBatches; i++) {
console.log("Processing batch", i, "of", totalBatches);
uint256 start = i * batchSize;
uint256 end = (i + 1) * batchSize;
if (end > totalElements) end = totalElements;

bytes32[] memory batchHashes = new bytes32[](end - start);
INSDomainPrice.Tier[] memory batchTiers = new INSDomainPrice.Tier[](end - start);

for (uint256 j = start; j < end; j++) {
batchHashes[j - start] = _lbHashes[j];
batchTiers[j - start] = _tiers[j];
}

vm.prank(overrider);
_domainPrice.bulkOverrideTiers(batchHashes, batchTiers);
}

_validateOverridenTiers();
_validateOtherDomainTiers();
}

function _validateOtherDomainTiers() internal logFn("_validating other domain tiers ...") {
if (network() == DefaultNetwork.RoninMainnet.key()) {
assertEq(uint8(_domainPrice.getTier("tudo")), uint8(INSDomainPrice.Tier.Tier2), "invalid tier for tudo");
assertEq(uint8(_domainPrice.getTier("duke")), uint8(INSDomainPrice.Tier.Tier2), "invalid tier for duke");
assertEq(uint8(_domainPrice.getTier("ace")), uint8(INSDomainPrice.Tier.Tier1), "invalid tier for ace");
assertEq(uint8(_domainPrice.getTier("dragon")), uint8(INSDomainPrice.Tier.Tier2), "invalid tier for dragon");
assertEq(uint8(_domainPrice.getTier("tokuda")), uint8(INSDomainPrice.Tier.Tier3), "invalid tier for tokuda");
assertEq(uint8(_domainPrice.getTier("metaverse")), uint8(INSDomainPrice.Tier.Tier2), "invalid tier for metaverse");
assertEq(uint8(_domainPrice.getTier("nuke")), uint8(INSDomainPrice.Tier.Tier2), "invalid tier for nuke");
assertEq(
uint8(_domainPrice.getTier("merchandising")), uint8(INSDomainPrice.Tier.Tier3), "invalid tier for merchandising"
);
}
}

function _validateOverridenTiers() internal logFn("_validating overriden tiers ...") {
IMulticall3.Call[] memory calls = new IMulticall3.Call[](_lbHashes.length);

for (uint256 i; i < _lbHashes.length; ++i) {
calls[i] = IMulticall3.Call({
target: address(_domainPrice),
callData: abi.encodeCall(_domainPrice.getTier, (_labels[i]))
});
}

(, bytes[] memory returnData) = _multicall.aggregate(calls);
INSDomainPrice.Tier[] memory tiers = new INSDomainPrice.Tier[](_lbHashes.length);

for (uint256 i; i < _lbHashes.length; ++i) {
tiers[i] = abi.decode(returnData[i], (INSDomainPrice.Tier));
assertEq(uint8(tiers[i]), uint8(_tiers[i]), string.concat("tier not set", vm.toString(i)));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { INSDomainPrice, RNSDomainPrice } from "@rns-contracts/RNSDomainPrice.sol";
import { Contract } from "../utils/Contract.sol";
import "./20240215_Migration.s.sol";

contract Migration__02_ResetCommunityNamesRenewalFees_RNSDomainPrice is Migration__20240215 {
bytes32[] internal _lbHashes;

function run() external {
RNSDomainPrice rnsDomainPrice = RNSDomainPrice(loadContract(Contract.RNSDomainPrice.key()));

_lbHashes = toLabelHashes(_labels);

address overrider = rnsDomainPrice.getRoleMember(rnsDomainPrice.OVERRIDER_ROLE(), 0);
uint256 batchSize = 100;
uint256 totalBatches = (_lbHashes.length + batchSize - 1) / batchSize;

for (uint256 batchIndex = 0; batchIndex < totalBatches; batchIndex++) {
uint256 startIndex = batchIndex * batchSize;
uint256 endIndex = startIndex + batchSize;
if (endIndex > _lbHashes.length) {
endIndex = _lbHashes.length;
}

bytes32[] memory batchLbHashes = new bytes32[](endIndex - startIndex);
uint256[] memory batchRenewalFees = new uint256[](endIndex - startIndex);

for (uint256 i = startIndex; i < endIndex; i++) {
batchLbHashes[i - startIndex] = _lbHashes[i];
batchRenewalFees[i - startIndex] = type(uint256).max;
}

vm.broadcast(overrider);
rnsDomainPrice.bulkOverrideRenewalFees(batchLbHashes, batchRenewalFees);
}
}

function _postCheck() internal override logFn("_postChecking ...") {
RNSDomainPrice rnsDomainPrice = RNSDomainPrice(loadContract(Contract.RNSDomainPrice.key()));

for (uint256 i; i < _lbHashes.length; ++i) {
vm.expectRevert(INSDomainPrice.RenewalFeeIsNotOverriden.selector);
rnsDomainPrice.getOverriddenRenewalFee(_labels[i]);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { StdStyle } from "forge-std/StdStyle.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { console2 as console } from "forge-std/console2.sol";
import { Contract } from "script/utils/Contract.sol";
import { Migration } from "script/Migration.s.sol";
import { RNSUnified } from "@rns-contracts/RNSUnified.sol";
import { INSDomainPrice, RNSDomainPrice } from "@rns-contracts/RNSDomainPrice.sol";
import { INSAuction, RNSAuction } from "@rns-contracts/RNSAuction.sol";
import { LibRNSDomain } from "@rns-contracts/libraries/LibRNSDomain.sol";
import { RNSOperation, RNSOperationDeploy } from "script/contracts/RNSOperationDeploy.s.sol";

contract Migration_03_DeployNewRNSOperation_RNSOperation is Migration {
using LibRNSDomain for string;
using StdStyle for *;

RNSUnified private rns;
RNSAuction private auction;
RNSOperation private rnsOperation;
RNSDomainPrice private domainPrice;

function run() public {
rnsOperation = new RNSOperationDeploy().run();

domainPrice = RNSDomainPrice(loadContract(Contract.RNSDomainPrice.key()));
rns = RNSUnified(loadContract(Contract.RNSUnified.key()));
auction = RNSAuction(loadContract(Contract.RNSAuction.key()));

address admin = rns.ownerOf(LibRNSDomain.RON_ID);
console.log("admin".yellow(), admin);

vm.broadcast(rnsOperation.owner());
rnsOperation.transferOwnership(admin);

vm.startBroadcast(admin);

rns.setApprovalForAll(address(rnsOperation), true);
auction.grantRole(auction.OPERATOR_ROLE(), address(rnsOperation));
rns.grantRole(rns.PROTECTED_SETTLER_ROLE(), address(rnsOperation));
domainPrice.grantRole(domainPrice.OVERRIDER_ROLE(), address(rnsOperation));

vm.stopBroadcast();
}

function _postCheck() internal override {
_validateBulkMint();
_validateOverridenTiers();
_validateBulkSetProtected();
_validateBulkOverrideRenewalFees();
_validateReclaimAuctionNames({ searchSize: 20 });
}

function _validateOverridenTiers() internal logFn("_validateOverridenTiers") {
string[] memory labels = new string[](5);
labels[0] = "heidi";
labels[1] = "luke";
labels[2] = "sophia";
labels[3] = "chief";
labels[4] = "slim";

for (uint256 i; i < labels.length; ++i) {
assertEq(
uint8(domainPrice.getTier(labels[i])),
uint8(INSDomainPrice.Tier.Tier1),
string.concat("invalid tier for auction label ", labels[i])
);
}
}

function _validateBulkOverrideRenewalFees() internal logFn("_validateBulkOverrideRenewalFees") {
string memory label = "tudo-provip-maximum-ultra";
string[] memory labels = new string[](1);
labels[0] = label;
uint256[] memory yearlyUSDPrices = new uint256[](1);
// 10 usd per year
yearlyUSDPrices[0] = 10;

vm.prank(rnsOperation.owner());
rnsOperation.bulkOverrideRenewalFees(labels, yearlyUSDPrices);

assertEq(domainPrice.getOverriddenRenewalFee(label), Math.mulDiv(yearlyUSDPrices[0], 1 ether, 365 days));
}

function _validateReclaimAuctionNames(uint256 searchSize) internal logFn("_validateReclaimAuctionNames") {
INSAuction.DomainAuction[] memory domainAuctions = new INSAuction.DomainAuction[](searchSize);
uint256[] memory reservedIds = new uint256[](searchSize);
for (uint256 i; i < searchSize; ++i) {
reservedIds[i] = rns.tokenOfOwnerByIndex(address(auction), i);
(domainAuctions[i],) = auction.getAuction(reservedIds[i]);
}

uint256 reclaimableAuctionNameId;
for (uint256 i; i < searchSize; ++i) {
if (domainAuctions[i].bid.bidder == address(0x0)) {
reclaimableAuctionNameId = reservedIds[i];
break;
}
}

address to = makeAddr("to");
address[] memory tos = new address[](1);
tos[0] = to;
string memory label = rns.getRecord(reclaimableAuctionNameId).immut.label;
console.log("reclaimable auction label", label);
string[] memory labels = new string[](1);
labels[0] = label;

vm.prank(rnsOperation.owner());
rnsOperation.reclaimUnbiddedNames({ tos: tos, labels: labels, allowFailure: false });
}

function _validateBulkMint() internal logFn("_validateBulkMint") {
address to = makeAddr("to");
address[] memory tos = new address[](1);
tos[0] = to;
string[] memory labels = new string[](1);
labels[0] = "tudo-provip-maximum-utra";
uint64 duration = uint64(3 days);

vm.prank(rnsOperation.owner());
rnsOperation.bulkMint(tos, labels, duration);

uint256 id = uint256(string.concat(labels[0], ".ron").namehash());
assertEq(rns.ownerOf(id), to);
}

function _validateBulkSetProtected() internal logFn("_validateBulkSetProtected") {
string[] memory labels = new string[](1);
labels[0] = "tudo-provip-maximum-utra";

bool shouldProtect = true;

vm.prank(rnsOperation.owner());
rnsOperation.bulkSetProtected(labels, shouldProtect);

uint256 id = uint256(string.concat(labels[0], ".ron").namehash());
assertTrue(rns.getRecord(id).mut.protected);

shouldProtect = false;

vm.prank(rnsOperation.owner());
rnsOperation.bulkSetProtected(labels, shouldProtect);

assertFalse(rns.getRecord(id).mut.protected);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { console2 as console } from "forge-std/console2.sol";
import { JSONParserLib } from "solady/utils/JSONParserLib.sol";
import { Migration, ISharedArgument } from "../Migration.s.sol";
import { LibRNSDomain } from "@rns-contracts/libraries/LibRNSDomain.sol";
import { INSDomainPrice } from "@rns-contracts/interfaces/INSDomainPrice.sol";

contract Migration__20240215 is Migration {
using JSONParserLib for *;
using LibRNSDomain for *;

string internal constant DATA_PATH = "script/data/517 Community names (Tier 1) - _3 characters.json";

INSDomainPrice.Tier[] internal _tiers;
string[] internal _labels;

constructor() { }

function toLabelHashes(string[] memory labels) internal pure returns (bytes32[] memory) {
bytes32[] memory hashes = new bytes32[](labels.length);
for (uint256 i; i < labels.length; ++i) {
hashes[i] = labels[i].hashLabel();
}
return hashes;
}

function toNameHashes(string[] memory labels) internal pure returns (uint256[] memory) {
uint256[] memory hashes = new uint256[](labels.length);
for (uint256 i; i < labels.length; ++i) {
hashes[i] = uint256(labels[i].namehash());
}
return hashes;
}

function _parseData(string memory path)
internal
view
returns (string[] memory labels, INSDomainPrice.Tier[] memory tiers)
{
string memory raw = vm.readFile(path);
JSONParserLib.Item memory communityNames = raw.parse().at('"communityNames"');
uint256 length = communityNames.size();
console.log("length", length);

labels = new string[](length);
tiers = new INSDomainPrice.Tier[](length);

for (uint256 i; i < length; ++i) {
tiers[i] = INSDomainPrice.Tier(uint8(vm.parseUint(communityNames.at(i).at('"tier"').value().decodeString())));
labels[i] = (communityNames.at(i).at('"domain"').value().decodeString());
}
}
}
Loading

0 comments on commit b413651

Please sign in to comment.