diff --git a/script/20240516-revoke-roles/01_DeployNew_OwnedMulticaller.s.sol b/script/20240516-revoke-roles/01_DeployNew_OwnedMulticaller_Mainnet.s.sol similarity index 56% rename from script/20240516-revoke-roles/01_DeployNew_OwnedMulticaller.s.sol rename to script/20240516-revoke-roles/01_DeployNew_OwnedMulticaller_Mainnet.s.sol index 6268344..00b79b8 100644 --- a/script/20240516-revoke-roles/01_DeployNew_OwnedMulticaller.s.sol +++ b/script/20240516-revoke-roles/01_DeployNew_OwnedMulticaller_Mainnet.s.sol @@ -4,17 +4,18 @@ pragma solidity ^0.8.19; import { console } from "forge-std/console.sol"; import { Contract } from "script/utils/Contract.sol"; import { Migration } from "script/Migration.s.sol"; +import { DefaultNetwork } from "@fdk/utils/DefaultNetwork.sol"; import { OwnedMulticaller, OwnedMulticallerDeploy } from "script/contracts/OwnedMulticallerDeploy.s.sol"; contract Migration__01_DeployNew_OwnedMulticaller is Migration { - address internal constant DUKE = 0x0F68eDBE14C8f68481771016d7E2871d6a35DE11; + address internal constant TUDO = 0x0Ebf93387093D7b7cDa9a4dE5d558507810af5eD; // TuDo's trezor OwnedMulticaller multicall; - function run() external { - multicall = new OwnedMulticallerDeploy().run(); + function run() external onlyOn(DefaultNetwork.RoninMainnet.key()) { + multicall = OwnedMulticaller(new OwnedMulticallerDeploy().overrideArgs(abi.encode(TUDO)).run()); } function _postCheck() internal virtual override { - assertEq(multicall.owner(), DUKE); + assertEq(multicall.owner(), TUDO); } } diff --git a/script/20240516-revoke-roles/01_DeployNew_OwnedMulticaller_Testnet.sol b/script/20240516-revoke-roles/01_DeployNew_OwnedMulticaller_Testnet.sol new file mode 100644 index 0000000..614c88f --- /dev/null +++ b/script/20240516-revoke-roles/01_DeployNew_OwnedMulticaller_Testnet.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { console } from "forge-std/console.sol"; +import { Contract } from "script/utils/Contract.sol"; +import { Migration } from "script/Migration.s.sol"; +import { DefaultNetwork } from "@fdk/utils/DefaultNetwork.sol"; +import { OwnedMulticaller, OwnedMulticallerDeploy } from "script/contracts/OwnedMulticallerDeploy.s.sol"; + +contract Migration__01_DeployNew_OwnedMulticaller_Testnet is Migration { + address internal constant DUKE = 0x968D0Cd7343f711216817E617d3f92a23dC91c07; + OwnedMulticaller multicall; + + function run() external onlyOn(DefaultNetwork.RoninTestnet.key()) { + multicall = OwnedMulticaller(new OwnedMulticallerDeploy().overrideArgs(abi.encode(DUKE)).run()); + } + + function _postCheck() internal virtual override { + assertEq(multicall.owner(), DUKE); + } +} diff --git a/script/20240516-revoke-roles/02_Revoke_Roles_Mainnet.s.sol b/script/20240516-revoke-roles/02_Revoke_Roles_Mainnet.s.sol new file mode 100644 index 0000000..f8e48e1 --- /dev/null +++ b/script/20240516-revoke-roles/02_Revoke_Roles_Mainnet.s.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { console } from "forge-std/console.sol"; +import { Migration } from "script/Migration.s.sol"; +import { Contract } from "script/utils/Contract.sol"; +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; +import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { AccessControlEnumerable } from "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; +import { LibRNSDomain } from "src/libraries/LibRNSDomain.sol"; +import { DefaultNetwork } from "@fdk/utils/DefaultNetwork.sol"; +import { RNSUnified } from "src/RNSUnified.sol"; +import { RNSAuction } from "src/RNSAuction.sol"; +import { NameChecker } from "src/NameChecker.sol"; +import { RNSDomainPrice } from "src/RNSDomainPrice.sol"; +import { PublicResolver } from "src/resolvers/PublicResolver.sol"; +import { RNSReverseRegistrar } from "src/RNSReverseRegistrar.sol"; +import { RONRegistrarController } from "src/RONRegistrarController.sol"; +import { OwnedMulticaller } from "src/utils/OwnedMulticaller.sol"; +import { INSDomainPrice } from "src/interfaces/INSDomainPrice.sol"; +import { OwnedMulticallerDeploy } from "script/contracts/OwnedMulticallerDeploy.s.sol"; +import { ErrorHandler } from "src/libraries/ErrorHandler.sol"; + +contract Migration__02_Revoke_Roles_Mainnet is Migration { + using Strings for *; + using ErrorHandler for bool; + using LibRNSDomain for string; + + address duke = 0x0F68eDBE14C8f68481771016d7E2871d6a35DE11; + address multisig = 0x1FF1edE0242317b8C4229fC59E64DD93952019ef; + + RNSUnified internal _rns; + RNSAuction internal _auction; + NameChecker internal _nameChecker; + RNSDomainPrice internal _domainPrice; + PublicResolver internal _publicResolver; + RNSReverseRegistrar internal _reverseRegistrar; + RONRegistrarController internal _ronController; + OwnedMulticaller internal _ownedMulticaller; + address internal _batchTransfer; + + function run() external onlyOn(DefaultNetwork.RoninMainnet.key()) { + _rns = RNSUnified(loadContract(Contract.RNSUnified.key())); + _auction = RNSAuction(loadContract(Contract.RNSAuction.key())); + _nameChecker = NameChecker(loadContract(Contract.NameChecker.key())); + _domainPrice = RNSDomainPrice(loadContract(Contract.RNSDomainPrice.key())); + _publicResolver = PublicResolver(loadContract(Contract.PublicResolver.key())); + _reverseRegistrar = RNSReverseRegistrar(loadContract(Contract.RNSReverseRegistrar.key())); + _ronController = RONRegistrarController(loadContract(Contract.RONRegistrarController.key())); + _ownedMulticaller = OwnedMulticaller(loadContract(Contract.OwnedMulticaller.key())); + _batchTransfer = loadContract(Contract.ERC721BatchTransfer.key()); + + address[] memory contracts = new address[](5); + contracts[0] = address(_domainPrice); + contracts[1] = address(_ronController); + contracts[2] = address(_nameChecker); + contracts[3] = address(_rns); + contracts[4] = address(_auction); + + address multicallOwner = _ownedMulticaller.owner(); + console.log("Multicaller owner:", multicallOwner); + + vm.startBroadcast(multicallOwner); + + address[] memory tos = new address[](3); + bytes[] memory callDatas = new bytes[](3); + uint256[] memory values = new uint256[](3); + + tos[0] = address(_rns); + tos[1] = address(_rns); + tos[2] = address(_rns); + + callDatas[0] = abi.encodeCall(ERC721.setApprovalForAll, (address(_auction), true)); + callDatas[1] = abi.encodeCall(ERC721.setApprovalForAll, (address(_ronController), true)); + callDatas[2] = abi.encodeCall(ERC721.setApprovalForAll, (address(_reverseRegistrar), true)); + + _ownedMulticaller.multicall(tos, callDatas, values); + + vm.stopBroadcast(); + + vm.startBroadcast(duke); + // Transfer .ron domain ownership to owned multicaller + uint256[] memory ids = new uint256[](3); + ids[0] = 0x0; + ids[1] = LibRNSDomain.RON_ID; + ids[2] = LibRNSDomain.ADDR_REVERSE_ID; + _rns.setApprovalForAll(_batchTransfer, true); + + // Bulk transfer .ron domain ownership to owned multicaller + (bool success, bytes memory returnOrRevertData) = _batchTransfer.call( + abi.encodeWithSignature("safeBatchTransfer(address,uint256[],address)", _rns, ids, _ownedMulticaller) + ); + success.handleRevert(returnOrRevertData); + + _rns.setApprovalForAll(_batchTransfer, false); + + _rns.setApprovalForAll(address(_auction), false); + _rns.setApprovalForAll(address(_ronController), false); + _rns.setApprovalForAll(address(_reverseRegistrar), false); + + uint256 length = contracts.length; + + for (uint256 i; i < length; i++) { + AccessControlEnumerable(contracts[i]).grantRole(0x0, multisig); + console.log("Duke will renounce his admin roles of contract:", vm.getLabel(contracts[i]), "manually"); + + assertTrue( + AccessControlEnumerable(contracts[i]).getRoleMemberCount(0x0) > 1, + string.concat("Role is empty", "contract: ", vm.toString(contracts[i])) + ); + } + + console.log("Revoke roles for domain price", 0xAdc6a8fEB5C53303323A1D0280c0a0d5F2e1a14D); + // Remove another admin roles: https://sky-mavis.slack.com/archives/C06C3HW1HS7/p1712812933009569 + AccessControlEnumerable(address(_domainPrice)).revokeRole(0x0, 0xAdc6a8fEB5C53303323A1D0280c0a0d5F2e1a14D); + + // Duke will do this manually + // Ownable(loadContract(Contract.OwnedMulticaller.key())).transferOwnership(multisig); + console.log( + "Duke will transfer to multisig his owner role of contract:", + vm.getLabel(loadContract(Contract.OwnedMulticaller.key())), + "manually" + ); + // Ownable(loadContract(Contract.RNSReverseRegistrar.key())).transferOwnership(multisig); + console.log( + "Duke will transfer to multisig his owner role of contract:", + vm.getLabel(loadContract(Contract.RNSReverseRegistrar.key())), + "manually" + ); + + vm.stopBroadcast(); + } + + function _postCheck() internal virtual override { + _validateController(); + _validateAuction(); + _validateReverseRegistrar(); + } + + function _validateReverseRegistrar() internal view logFn("validateReverseRegistrar") { + assertEq(_rns.getApproved(LibRNSDomain.ADDR_REVERSE_ID), address(_reverseRegistrar)); + } + + function _validateController() internal logFn("_validateController") { + Account memory user = makeAccount("tudo"); + uint64 duration = 30 days; + bytes32 secret = keccak256("secret"); + string memory domain = "tudo-controller-promax"; + + bytes[] memory data; + bytes32 commitment = + _ronController.computeCommitment(domain, user.addr, duration, secret, address(_publicResolver), data, true); + + (, uint256 ronPrice) = _ronController.rentPrice(domain, duration); + console.log("domain price:", ronPrice); + vm.deal(user.addr, ronPrice); + + vm.startPrank(user.addr); + _ronController.commit(commitment); + vm.warp(block.timestamp + 1 hours); + _ronController.register{ value: ronPrice }( + domain, user.addr, duration, secret, address(_publicResolver), data, true + ); + vm.stopPrank(); + + uint256 expectedId = uint256(string.concat(domain, ".ron").namehash()); + assertEq(_rns.ownerOf(expectedId), user.addr); + console.log(unicode"✅ Controller checks are passed"); + } + + function _validateAuction() internal logFn("validateAuction") { + address operator = _auction.getRoleMember(_auction.OPERATOR_ROLE(), 0); + string[] memory domainNames = new string[](1); + string memory domainName = "tudo-reserved-provip"; + domainNames[0] = domainName; + bytes32[] memory lbHashes = new bytes32[](1); + lbHashes[0] = LibRNSDomain.hashLabel(domainName); + uint256[] memory setTypes = new uint256[](1); + uint256[] memory ronPrices = new uint256[](1); + bytes32[] memory proofHashes = new bytes32[](1); + ronPrices[0] = _domainPrice.convertUSDToRON(2e18); + + vm.startPrank(operator); + + _auction.bulkRegister(domainNames); + _domainPrice.bulkSetDomainPrice(lbHashes, ronPrices, proofHashes, setTypes); + + uint256 id = LibRNSDomain.toId(LibRNSDomain.RON_ID, domainNames[0]); + (, INSDomainPrice.UnitPrice memory tax) = _domainPrice.getRenewalFee(domainName, 365 days); + assertTrue(tax.usd != 0, "reversed name not have tax"); + + vm.stopPrank(); + + assertTrue(_auction.reserved(id), "invalid bulkRegister"); + assertEq(_rns.getRecord(id).mut.expiry, _rns.MAX_EXPIRY(), "invalid expiry time"); + + console.log(unicode"✅ Auction checks are passed"); + } +} diff --git a/script/20240516-revoke-roles/02_Revoke_Roles.s.sol b/script/20240516-revoke-roles/02_Revoke_Roles_Testnet.sol similarity index 95% rename from script/20240516-revoke-roles/02_Revoke_Roles.s.sol rename to script/20240516-revoke-roles/02_Revoke_Roles_Testnet.sol index af04c10..c6a6ae1 100644 --- a/script/20240516-revoke-roles/02_Revoke_Roles.s.sol +++ b/script/20240516-revoke-roles/02_Revoke_Roles_Testnet.sol @@ -20,12 +20,12 @@ import { RONRegistrarController } from "src/RONRegistrarController.sol"; import { OwnedMulticaller } from "src/utils/OwnedMulticaller.sol"; import { INSDomainPrice } from "src/interfaces/INSDomainPrice.sol"; -contract Migration__01_Revoke_Roles is Migration { +contract Migration__01_Revoke_Roles_Testnet is Migration { using Strings for *; using LibRNSDomain for string; - address duke = 0x0F68eDBE14C8f68481771016d7E2871d6a35DE11; - address multisig = 0x1FF1edE0242317b8C4229fC59E64DD93952019ef; + address duke = 0x968D0Cd7343f711216817E617d3f92a23dC91c07; + address multisig = 0x792428597158d73fF55333659957057f93362dfc; RNSUnified internal _rns; RNSAuction internal _auction; @@ -36,7 +36,7 @@ contract Migration__01_Revoke_Roles is Migration { RONRegistrarController internal _ronController; OwnedMulticaller internal _ownedMulticaller; - function run() external onlyOn(DefaultNetwork.RoninMainnet.key()) { + function run() external onlyOn(DefaultNetwork.RoninTestnet.key()) { _rns = RNSUnified(loadContract(Contract.RNSUnified.key())); _auction = RNSAuction(loadContract(Contract.RNSAuction.key())); _nameChecker = NameChecker(loadContract(Contract.NameChecker.key())); @@ -85,7 +85,7 @@ contract Migration__01_Revoke_Roles is Migration { console.log("Duke will renounce his admin roles of contract:", vm.getLabel(contracts[i]), "manually"); assertTrue( - AccessControlEnumerable(contracts[i]).getRoleMemberCount(0x0) > 0, + AccessControlEnumerable(contracts[i]).getRoleMemberCount(0x0) > 1, string.concat("Role is empty", "contract: ", vm.toString(contracts[i])) ); } @@ -109,7 +109,7 @@ contract Migration__01_Revoke_Roles is Migration { function _postCheck() internal virtual override { _validateController(); - _validateAuction(); + _validateDomainPrice(); _validateReverseRegistrar(); } @@ -144,7 +144,7 @@ contract Migration__01_Revoke_Roles is Migration { console.log(unicode"✅ Controller checks are passed"); } - function _validateAuction() internal logFn("validateAuction") { + function _validateDomainPrice() internal logFn("_validateDomainPrice") { address operator = _auction.getRoleMember(_auction.OPERATOR_ROLE(), 0); string[] memory domainNames = new string[](1); string memory domainName = "tudo-reserved-provip"; diff --git a/script/GeneralConfig.sol b/script/GeneralConfig.sol index d5f0870..d13cb46 100644 --- a/script/GeneralConfig.sol +++ b/script/GeneralConfig.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.19; import { BaseGeneralConfig } from "@fdk/BaseGeneralConfig.sol"; import { Contract } from "./utils/Contract.sol"; +import { DefaultNetwork } from "@fdk/utils/DefaultNetwork.sol"; contract GeneralConfig is BaseGeneralConfig { constructor() BaseGeneralConfig("", "deployments/") { } @@ -18,6 +19,16 @@ contract GeneralConfig is BaseGeneralConfig { _mapContractName(Contract.RNSReverseRegistrar); _mapContractName(Contract.RONRegistrarController); _mapContractName(Contract.RNSCommission); + _mapContractName(Contract.ERC721BatchTransfer); + + // Verify: https://app.roninchain.com/address/0x2368dfED532842dB89b470fdE9Fd584d48D4F644 + setAddress( + DefaultNetwork.RoninMainnet.key(), Contract.ERC721BatchTransfer.key(), 0x2368dfED532842dB89b470fdE9Fd584d48D4F644 + ); + // Verify: https://saigon-app.roninchain.com/address/0x2E889348bD37f192063Bfec8Ff39bD3635949e20 + setAddress( + DefaultNetwork.RoninTestnet.key(), Contract.ERC721BatchTransfer.key(), 0x2E889348bD37f192063Bfec8Ff39bD3635949e20 + ); } function _mapContractName(Contract contractEnum) internal { diff --git a/script/utils/Contract.sol b/script/utils/Contract.sol index 15042b5..cfef2d6 100644 --- a/script/utils/Contract.sol +++ b/script/utils/Contract.sol @@ -14,7 +14,8 @@ enum Contract { OwnedMulticaller, RNSReverseRegistrar, RONRegistrarController, - RNSCommission + RNSCommission, + ERC721BatchTransfer } using { key, name } for Contract global; @@ -34,5 +35,6 @@ function name(Contract contractEnum) pure returns (string memory) { if (contractEnum == Contract.RNSReverseRegistrar) return "RNSReverseRegistrar"; if (contractEnum == Contract.RONRegistrarController) return "RONRegistrarController"; if (contractEnum == Contract.RNSCommission) return "RNSCommission"; + if (contractEnum == Contract.ERC721BatchTransfer) return "ERC721BatchTransfer"; revert("Contract: Unknown contract"); }