diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 286ea33..b20b9e0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,6 +8,7 @@ on: env: FOUNDRY_PROFILE: ci BASE_SEPOLIA_RPC_URL: "https://sepolia.base.org" + BASE_MAINNET_RPC_URL: "https://mainnet.base.org" jobs: forge-test: diff --git a/foundry.toml b/foundry.toml index 353b07d..f5dd4e0 100644 --- a/foundry.toml +++ b/foundry.toml @@ -45,6 +45,7 @@ auto_detect_remappings = false [rpc_endpoints] sepolia="${SEPOLIA_RPC_URL}" base-sepolia="${BASE_SEPOLIA_RPC_URL}" +base-mainnet="${BASE_MAINNET_RPC_URL}" [etherscan] sepolia={url = "https://api-sepolia.etherscan.io/api", key = "${ETHERSCAN_API_KEY}"} diff --git a/test/Fork/ENSIP19DataMigrations.sol b/test/Fork/AbstractENSIP19DataMigrations.t.sol similarity index 63% rename from test/Fork/ENSIP19DataMigrations.sol rename to test/Fork/AbstractENSIP19DataMigrations.t.sol index 7831902..1110461 100644 --- a/test/Fork/ENSIP19DataMigrations.sol +++ b/test/Fork/AbstractENSIP19DataMigrations.t.sol @@ -11,21 +11,19 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {RegistrarController} from "src/L2/RegistrarController.sol"; import {ReverseRegistrar} from "src/L2/ReverseRegistrar.sol"; import {L2Resolver} from "src/L2/L2Resolver.sol"; -import {BASE_REVERSE_NODE} from "src/util/Constants.sol"; import {MigrationController} from "src/L2/MigrationController.sol"; import {Sha3} from "src/lib/Sha3.sol"; -import {BaseSepoliaForkBase} from "./BaseSepoliaForkBase.t.sol"; -import {BaseSepolia as BaseSepoliaConstants} from "test/Fork/BaseSepoliaConstants.sol"; +import {AbstractForkSuite} from "./AbstractForkSuite.t.sol"; -contract ENSIP19DataMigrations is BaseSepoliaForkBase { +abstract contract AbstractENSIP19DataMigrations is AbstractForkSuite { function test_migration_controller_setBaseForwardAddr() public { string memory name = "migratefwd"; bytes32 root = legacyController.rootNode(); bytes32 node = keccak256(abi.encodePacked(root, _labelFor(name))); // Register a name with legacy resolver - RegistrarController legacyRC = RegistrarController(BaseSepoliaConstants.LEGACY_GA_CONTROLLER); + RegistrarController legacyRC = RegistrarController(LEGACY_GA_CONTROLLER); uint256 price = legacyRC.registerPrice(name, 365 days); vm.deal(user, price); vm.prank(user); @@ -34,7 +32,7 @@ contract ENSIP19DataMigrations is BaseSepoliaForkBase { name: name, owner: user, duration: 365 days, - resolver: BaseSepoliaConstants.LEGACY_L2_RESOLVER, + resolver: LEGACY_L2_RESOLVER, data: new bytes[](0), reverseRecord: false }) @@ -42,48 +40,46 @@ contract ENSIP19DataMigrations is BaseSepoliaForkBase { // Set a legacy EVM addr record (ETH_COINTYPE) on the resolver so there is something to migrate vm.prank(user); - AddrResolver(BaseSepoliaConstants.LEGACY_L2_RESOLVER).setAddr(node, user); + AddrResolver(LEGACY_L2_RESOLVER).setAddr(node, user); // Configure MigrationController as registrar controller on the resolver (as L2 owner) vm.prank(L2_OWNER); - L2Resolver(BaseSepoliaConstants.LEGACY_L2_RESOLVER).setRegistrarController( - BaseSepoliaConstants.MIGRATION_CONTROLLER - ); + L2Resolver(LEGACY_L2_RESOLVER).setRegistrarController(MIGRATION_CONTROLLER); - uint256 coinType = MigrationController(BaseSepoliaConstants.MIGRATION_CONTROLLER).coinType(); + uint256 coinType = MigrationController(MIGRATION_CONTROLLER).coinType(); // Pre: ENSIP-11 (coinType) record should be empty - bytes memory beforeBytes = AddrResolver(BaseSepoliaConstants.LEGACY_L2_RESOLVER).addr(node, coinType); + bytes memory beforeBytes = AddrResolver(LEGACY_L2_RESOLVER).addr(node, coinType); assertEq(beforeBytes.length, 0, "pre: ensip-11 addr already set"); // Call MigrationController as owner (l2_owner_address) bytes32[] memory nodes = new bytes32[](1); nodes[0] = node; vm.prank(L2_OWNER); - MigrationController(BaseSepoliaConstants.MIGRATION_CONTROLLER).setBaseForwardAddr(nodes); + MigrationController(MIGRATION_CONTROLLER).setBaseForwardAddr(nodes); // Post: ENSIP-11 (coinType) forward addr set - bytes memory afterBytes = AddrResolver(BaseSepoliaConstants.LEGACY_L2_RESOLVER).addr(node, coinType); + bytes memory afterBytes = AddrResolver(LEGACY_L2_RESOLVER).addr(node, coinType); assertGt(afterBytes.length, 0, "post: ensip-11 addr not set"); } function test_l2_reverse_registrar_with_migration_batchSetName() public { string memory name = "migraterev"; - // Claim/set old reverse name via legacy flow - vm.prank(user); - ReverseRegistrar(BaseSepoliaConstants.LEGACY_REVERSE_REGISTRAR).setNameForAddr( - user, user, BaseSepoliaConstants.LEGACY_L2_RESOLVER, _fullName(name) - ); + // Claim/set old reverse name via legacy flow as the user (persist prank across nested calls) + vm.startPrank(user); + ReverseRegistrar(LEGACY_REVERSE_REGISTRAR).setNameForAddr(user, user, LEGACY_L2_RESOLVER, _fullName(name)); + vm.stopPrank(); address rrOwner = Ownable(ENS_L2_REVERSE_REGISTRAR).owner(); address[] memory addrs = new address[](1); addrs[0] = user; - (, bytes32 calculatedBaseReverseNode) = NameEncoder.dnsEncodeName("80014a34.reverse"); - console2.logBytes32(calculatedBaseReverseNode); - bytes32 node = keccak256(abi.encodePacked(calculatedBaseReverseNode, Sha3.hexAddress(user))); + // Calculate node under chain-specific reverse parent + bytes32 parent = baseReverseParentNode(); + console2.logBytes32(parent); + bytes32 node = keccak256(abi.encodePacked(parent, Sha3.hexAddress(user))); console2.logBytes32(node); vm.prank(rrOwner); diff --git a/test/Fork/ENSIP19LegacyFlows.t.sol b/test/Fork/AbstractENSIP19LegacyFlows.t.sol similarity index 87% rename from test/Fork/ENSIP19LegacyFlows.t.sol rename to test/Fork/AbstractENSIP19LegacyFlows.t.sol index 47ed377..4d1f567 100644 --- a/test/Fork/ENSIP19LegacyFlows.t.sol +++ b/test/Fork/AbstractENSIP19LegacyFlows.t.sol @@ -7,10 +7,9 @@ import {NameResolver} from "ens-contracts/resolvers/profiles/NameResolver.sol"; import {IReverseRegistrar} from "src/L2/interface/IReverseRegistrar.sol"; import {RegistrarController} from "src/L2/RegistrarController.sol"; -import {BaseSepoliaForkBase} from "./BaseSepoliaForkBase.t.sol"; -import {BaseSepolia as BaseSepoliaConstants} from "./BaseSepoliaConstants.sol"; +import {AbstractForkSuite} from "./AbstractForkSuite.t.sol"; -contract ENSIP19LegacyFlows is BaseSepoliaForkBase { +abstract contract AbstractENSIP19LegacyFlows is AbstractForkSuite { function test_register_name_on_legacy() public { string memory name = "forkleg"; bytes32 root = legacyController.rootNode(); @@ -59,12 +58,13 @@ contract ENSIP19LegacyFlows is BaseSepoliaForkBase { vm.prank(user); legacyController.register{value: price}(req); - // Set primary via legacy ReverseRegistrar directly - vm.prank(user); + // Set primary via legacy ReverseRegistrar directly (persist prank across nested calls) + vm.startPrank(user); IReverseRegistrar(LEGACY_REVERSE_REGISTRAR).setNameForAddr(user, user, LEGACY_L2_RESOLVER, _fullName(name)); + vm.stopPrank(); // Validate reverse record was set on the legacy resolver - bytes32 baseRevNode = _baseReverseNode(user, BaseSepoliaConstants.BASE_SEPOLIA_REVERSE_NODE); + bytes32 baseRevNode = _baseReverseNode(user, baseReverseParentNode()); string memory storedName = NameResolver(LEGACY_L2_RESOLVER).name(baseRevNode); assertEq(keccak256(bytes(storedName)), keccak256(bytes(_fullName(name))), "reverse name not set"); @@ -93,9 +93,9 @@ contract ENSIP19LegacyFlows is BaseSepoliaForkBase { legacyController.register{value: price}(req); // Assert reverse was set by the controller calling the ReverseRegistrar - bytes32 baseRevNode = _baseReverseNode(user, BaseSepoliaConstants.BASE_SEPOLIA_REVERSE_NODE); + bytes32 baseRevNode = _baseReverseNode(user, baseReverseParentNode()); string memory storedName = NameResolver(LEGACY_L2_RESOLVER).name(baseRevNode); - string memory expectedFull = string.concat(name, legacyController.rootName()); + string memory expectedFull = _fullName(name); assertEq(keccak256(bytes(storedName)), keccak256(bytes(expectedFull)), "reverse name not set by controller"); // Also verify forward resolver/owner as a sanity check diff --git a/test/Fork/ENSIP19NewFlows.sol b/test/Fork/AbstractENSIP19NewFlows.t.sol similarity index 84% rename from test/Fork/ENSIP19NewFlows.sol rename to test/Fork/AbstractENSIP19NewFlows.t.sol index 21433c1..5adb7ec 100644 --- a/test/Fork/ENSIP19NewFlows.sol +++ b/test/Fork/AbstractENSIP19NewFlows.t.sol @@ -7,12 +7,9 @@ import {NameResolver} from "ens-contracts/resolvers/profiles/NameResolver.sol"; import {UpgradeableRegistrarController} from "src/L2/UpgradeableRegistrarController.sol"; -import {BaseSepoliaForkBase} from "./BaseSepoliaForkBase.t.sol"; -import {BaseSepolia as BaseSepoliaConstants} from "./BaseSepoliaConstants.sol"; - -contract ENSIP19NewFlows is BaseSepoliaForkBase { - uint256 internal constant BASE_SEPOLIA_COINTYPE = 2147568180; +import {AbstractForkSuite} from "./AbstractForkSuite.t.sol"; +abstract contract AbstractENSIP19NewFlows is AbstractForkSuite { function test_register_on_new_sets_forward_records_ensip11() public { string memory name = "forknewfwd"; bytes32 root = legacyController.rootNode(); @@ -24,7 +21,7 @@ contract ENSIP19NewFlows is BaseSepoliaForkBase { data[0] = abi.encodeWithSelector(setAddrDefaultSel, node, user); // setAddr(bytes32,uint256,bytes) bytes4 setAddrCointypeSel = bytes4(keccak256("setAddr(bytes32,uint256,bytes)")); - data[1] = abi.encodeWithSelector(setAddrCointypeSel, node, BASE_SEPOLIA_COINTYPE, _addressToBytes(user)); + data[1] = abi.encodeWithSelector(setAddrCointypeSel, node, baseCoinType(), _addressToBytes(user)); UpgradeableRegistrarController.RegisterRequest memory req = UpgradeableRegistrarController.RegisterRequest({ name: name, @@ -49,7 +46,7 @@ contract ENSIP19NewFlows is BaseSepoliaForkBase { assertEq(resolverNow, UPGRADEABLE_L2_RESOLVER_PROXY, "resolver should be upgradeable L2 resolver"); assertEq(ownerNow, user, "owner should be user"); - bytes memory coinAddr = AddrResolver(UPGRADEABLE_L2_RESOLVER_PROXY).addr(node, BASE_SEPOLIA_COINTYPE); + bytes memory coinAddr = AddrResolver(UPGRADEABLE_L2_RESOLVER_PROXY).addr(node, baseCoinType()); assertEq(coinAddr.length, 20, "ensip-11 addr length"); assertEq(address(bytes20(coinAddr)), user, "ensip-11 addr matches user"); assertEq(AddrResolver(UPGRADEABLE_L2_RESOLVER_PROXY).addr(node), user, "default addr matches user"); @@ -77,7 +74,7 @@ contract ENSIP19NewFlows is BaseSepoliaForkBase { vm.prank(user); upgradeableController.register{value: price}(req); - bytes32 baseRevNode = _baseReverseNode(user, BaseSepoliaConstants.BASE_SEPOLIA_REVERSE_NODE); + bytes32 baseRevNode = _baseReverseNode(user, baseReverseParentNode()); string memory storedName = NameResolver(LEGACY_L2_RESOLVER).name(baseRevNode); string memory expectedFull = string.concat(name, legacyController.rootName()); assertEq(keccak256(bytes(storedName)), keccak256(bytes(expectedFull)), "legacy reverse name not set"); @@ -93,27 +90,20 @@ contract ENSIP19NewFlows is BaseSepoliaForkBase { function test_set_primary_on_new_writes_both_paths_with_signature() public { string memory name = "forknewprim"; - string memory fullName = string.concat(name, legacyController.rootName()); + string memory fullName = _fullName(name); uint256[] memory coinTypes = new uint256[](1); - coinTypes[0] = BASE_SEPOLIA_COINTYPE; + coinTypes[0] = baseCoinType(); uint256 expiry = block.timestamp + 30 minutes; bytes memory signature = _buildL2ReverseSignature(fullName, coinTypes, expiry); vm.prank(user); upgradeableController.setReverseRecord(name, expiry, coinTypes, signature); - bytes32 baseRevNode = _baseReverseNode(user, BaseSepoliaConstants.BASE_SEPOLIA_REVERSE_NODE); + bytes32 baseRevNode = _baseReverseNode(user, baseReverseParentNode()); string memory storedLegacy = NameResolver(LEGACY_L2_RESOLVER).name(baseRevNode); assertEq(keccak256(bytes(storedLegacy)), keccak256(bytes(fullName)), "legacy reverse not set"); string memory l2Name = l2ReverseRegistrar.nameForAddr(user); assertEq(keccak256(bytes(l2Name)), keccak256(bytes(fullName)), "l2 reverse not set"); } - - function _addressToBytes(address a) internal pure returns (bytes memory b) { - b = new bytes(20); - assembly { - mstore(add(b, 32), mul(a, exp(256, 12))) - } - } } diff --git a/test/Fork/AbstractForkSuite.t.sol b/test/Fork/AbstractForkSuite.t.sol new file mode 100644 index 0000000..dfdea0b --- /dev/null +++ b/test/Fork/AbstractForkSuite.t.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {Test} from "forge-std/Test.sol"; +import {ENS} from "ens-contracts/registry/ENS.sol"; +import {NameResolver} from "ens-contracts/resolvers/profiles/NameResolver.sol"; + +import {RegistrarController} from "src/L2/RegistrarController.sol"; +import {UpgradeableRegistrarController} from "src/L2/UpgradeableRegistrarController.sol"; +import {IL2ReverseRegistrar} from "src/L2/interface/IL2ReverseRegistrar.sol"; +import {IReverseRegistrar} from "src/L2/interface/IReverseRegistrar.sol"; +import {Sha3} from "src/lib/Sha3.sol"; +import {BASE_ETH_NODE} from "src/util/Constants.sol"; + +abstract contract AbstractForkSuite is Test { + // Network configuration hooks + function forkAlias() internal pure virtual returns (string memory); + + function registry() internal pure virtual returns (address); + function baseRegistrar() internal pure virtual returns (address); + function legacyGaController() internal pure virtual returns (address); + function legacyL2Resolver() internal pure virtual returns (address); + function legacyReverseRegistrar() internal pure virtual returns (address); + + function upgradeableControllerProxy() internal pure virtual returns (address); + function upgradeableL2ResolverProxy() internal pure virtual returns (address); + + function ensL2ReverseRegistrar() internal pure virtual returns (address); + function l2Owner() internal pure virtual returns (address); + function migrationController() internal pure virtual returns (address); + + function baseCoinType() internal pure virtual returns (uint256); + function baseReverseParentNode() internal pure virtual returns (bytes32); + + // Actors + uint256 internal userPk; + address internal user; + + // Interfaces + RegistrarController internal legacyController; + UpgradeableRegistrarController internal upgradeableController; + NameResolver internal legacyResolver; + IL2ReverseRegistrar internal l2ReverseRegistrar; + + // Aliased constants for readability in scenarios + address internal REGISTRY; + address internal BASE_REGISTRAR; + address internal LEGACY_GA_CONTROLLER; + address internal LEGACY_L2_RESOLVER; + address internal LEGACY_REVERSE_REGISTRAR; + address internal UPGRADEABLE_CONTROLLER_PROXY; + address internal UPGRADEABLE_L2_RESOLVER_PROXY; + address internal ENS_L2_REVERSE_REGISTRAR; + address internal L2_OWNER; + address internal MIGRATION_CONTROLLER; + + function setUp() public virtual { + vm.createSelectFork(forkAlias()); + + // Bind constants + REGISTRY = registry(); + BASE_REGISTRAR = baseRegistrar(); + LEGACY_GA_CONTROLLER = legacyGaController(); + LEGACY_L2_RESOLVER = legacyL2Resolver(); + LEGACY_REVERSE_REGISTRAR = legacyReverseRegistrar(); + UPGRADEABLE_CONTROLLER_PROXY = upgradeableControllerProxy(); + UPGRADEABLE_L2_RESOLVER_PROXY = upgradeableL2ResolverProxy(); + ENS_L2_REVERSE_REGISTRAR = ensL2ReverseRegistrar(); + L2_OWNER = l2Owner(); + MIGRATION_CONTROLLER = migrationController(); + + // Create a deterministic EOA we control for signing + userPk = uint256(keccak256("basenames.fork.user")); + user = vm.addr(userPk); + + legacyController = RegistrarController(LEGACY_GA_CONTROLLER); + upgradeableController = UpgradeableRegistrarController(UPGRADEABLE_CONTROLLER_PROXY); + legacyResolver = NameResolver(LEGACY_L2_RESOLVER); + l2ReverseRegistrar = IL2ReverseRegistrar(ENS_L2_REVERSE_REGISTRAR); + } + + function _labelFor(string memory name) internal pure returns (bytes32) { + return keccak256(bytes(name)); + } + + function _nodeFor(string memory name) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(BASE_ETH_NODE, _labelFor(name))); + } + + function _fullName(string memory name) internal view returns (string memory) { + // Use controller-provided root name to avoid hardcoding suffixes + return string.concat(name, legacyController.rootName()); + } + + function _baseReverseNode(address addr, bytes32 baseReverseParent) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(baseReverseParent, Sha3.hexAddress(addr))); + } + + // Build a signature for ENS L2 Reverse Registrar setNameForAddrWithSignature, EIP-191 style + function _buildL2ReverseSignature(string memory fullName, uint256[] memory coinTypes, uint256 expiry) + internal + view + returns (bytes memory) + { + bytes4 selector = IL2ReverseRegistrar.setNameForAddrWithSignature.selector; + bytes32 inner = + keccak256(abi.encodePacked(ENS_L2_REVERSE_REGISTRAR, selector, user, expiry, fullName, coinTypes)); + bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", inner)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(userPk, digest); + return abi.encodePacked(r, s, v); + } + + function _addressToBytes(address a) internal pure returns (bytes memory b) { + b = new bytes(20); + assembly { + mstore(add(b, 32), mul(a, exp(256, 12))) + } + } +} diff --git a/test/Fork/BaseMainnetConfig.t.sol b/test/Fork/BaseMainnetConfig.t.sol new file mode 100644 index 0000000..e83c812 --- /dev/null +++ b/test/Fork/BaseMainnetConfig.t.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {AbstractForkSuite} from "./AbstractForkSuite.t.sol"; +import {BaseMainnet as C} from "./BaseMainnetConstants.sol"; + +abstract contract BaseMainnetConfig is AbstractForkSuite { + function forkAlias() internal pure override returns (string memory) { + return "base-mainnet"; + } + + function registry() internal pure override returns (address) { + return C.REGISTRY; + } + + function baseRegistrar() internal pure override returns (address) { + return C.BASE_REGISTRAR; + } + + function legacyGaController() internal pure override returns (address) { + return C.LEGACY_GA_CONTROLLER; + } + + function legacyL2Resolver() internal pure override returns (address) { + return C.LEGACY_L2_RESOLVER; + } + + function legacyReverseRegistrar() internal pure override returns (address) { + return C.LEGACY_REVERSE_REGISTRAR; + } + + function upgradeableControllerProxy() internal pure override returns (address) { + return C.UPGRADEABLE_CONTROLLER_PROXY; + } + + function upgradeableL2ResolverProxy() internal pure override returns (address) { + return C.UPGRADEABLE_L2_RESOLVER_PROXY; + } + + function ensL2ReverseRegistrar() internal pure override returns (address) { + return C.ENS_L2_REVERSE_REGISTRAR; + } + + function l2Owner() internal pure override returns (address) { + return C.L2_OWNER; + } + + function migrationController() internal pure override returns (address) { + return C.MIGRATION_CONTROLLER; + } + + function baseCoinType() internal pure override returns (uint256) { + return C.BASE_MAINNET_COINTYPE; + } + + function baseReverseParentNode() internal pure override returns (bytes32) { + return C.BASE_MAINNET_REVERSE_NODE; + } +} diff --git a/test/Fork/BaseMainnetConstants.sol b/test/Fork/BaseMainnetConstants.sol new file mode 100644 index 0000000..cf41028 --- /dev/null +++ b/test/Fork/BaseMainnetConstants.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +library BaseMainnet { + // ENS / Basenames addresses on Base Mainnet + address constant REGISTRY = 0xB94704422c2a1E396835A571837Aa5AE53285a95; + address constant BASE_REGISTRAR = 0x03c4738Ee98aE44591e1A4A4F3CaB6641d95DD9a; + address constant LEGACY_GA_CONTROLLER = 0x4cCb0BB02FCABA27e82a56646E81d8c5bC4119a5; + address constant LEGACY_L2_RESOLVER = 0xC6d566A56A1aFf6508b41f6c90ff131615583BCD; + // ReverseRegistrar with correct reverse node configured for Base Mainnet + address constant LEGACY_REVERSE_REGISTRAR = 0x79EA96012eEa67A83431F1701B3dFf7e37F9E282; + + address constant UPGRADEABLE_CONTROLLER_PROXY = 0xa7d2607c6BD39Ae9521e514026CBB078405Ab322; + address constant UPGRADEABLE_L2_RESOLVER_PROXY = 0x426fA03fB86E510d0Dd9F70335Cf102a98b10875; + + // ENS L2 Reverse Registrar (ENS-managed) on Base Mainnet + address constant ENS_L2_REVERSE_REGISTRAR = 0x0000000000D8e504002cC26E3Ec46D81971C1664; + + // Ops / controllers + address constant L2_OWNER = 0xf9BbA2F07a2c95fC4225f1CAeC76E6BF04B463e9; + address constant MIGRATION_CONTROLLER = 0x8d5ef54f900c82da119B4a7F960A92F3Fa8daB43; + + // ENSIP-11 Base Mainnet cointype + uint256 constant BASE_MAINNET_COINTYPE = 2147492101; // 0x80002105 + + // ENSIP-19 Base Mainnet reverse parent node: namehash("80002105.reverse") + bytes32 constant BASE_MAINNET_REVERSE_NODE = 0x08d9b0993eb8c4da57c37a4b84a6e384c2623114ff4e9370ed51c9b8935109ba; +} diff --git a/test/Fork/BaseSepoliaConfig.t.sol b/test/Fork/BaseSepoliaConfig.t.sol new file mode 100644 index 0000000..ca5949f --- /dev/null +++ b/test/Fork/BaseSepoliaConfig.t.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {AbstractForkSuite} from "./AbstractForkSuite.t.sol"; +import {BaseSepolia as C} from "./BaseSepoliaConstants.sol"; + +abstract contract BaseSepoliaConfig is AbstractForkSuite { + function forkAlias() internal pure override returns (string memory) { + return "base-sepolia"; + } + + function registry() internal pure override returns (address) { + return C.REGISTRY; + } + + function baseRegistrar() internal pure override returns (address) { + return C.BASE_REGISTRAR; + } + + function legacyGaController() internal pure override returns (address) { + return C.LEGACY_GA_CONTROLLER; + } + + function legacyL2Resolver() internal pure override returns (address) { + return C.LEGACY_L2_RESOLVER; + } + + function legacyReverseRegistrar() internal pure override returns (address) { + return C.LEGACY_REVERSE_REGISTRAR; + } + + function upgradeableControllerProxy() internal pure override returns (address) { + return C.UPGRADEABLE_CONTROLLER_PROXY; + } + + function upgradeableL2ResolverProxy() internal pure override returns (address) { + return C.UPGRADEABLE_L2_RESOLVER_PROXY; + } + + function ensL2ReverseRegistrar() internal pure override returns (address) { + return C.ENS_L2_REVERSE_REGISTRAR; + } + + function l2Owner() internal pure override returns (address) { + return C.L2_OWNER; + } + + function migrationController() internal pure override returns (address) { + return C.MIGRATION_CONTROLLER; + } + + function baseCoinType() internal pure override returns (uint256) { + return C.BASE_SEPOLIA_COINTYPE; + } + + function baseReverseParentNode() internal pure override returns (bytes32) { + return C.BASE_SEPOLIA_REVERSE_NODE; + } +} diff --git a/test/Fork/BaseSepoliaForkBase.t.sol b/test/Fork/BaseSepoliaForkBase.t.sol deleted file mode 100644 index b9d3223..0000000 --- a/test/Fork/BaseSepoliaForkBase.t.sol +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import {Test} from "forge-std/Test.sol"; -import {ENS} from "ens-contracts/registry/ENS.sol"; -import {NameResolver} from "ens-contracts/resolvers/profiles/NameResolver.sol"; - -import {RegistrarController} from "src/L2/RegistrarController.sol"; -import {UpgradeableRegistrarController} from "src/L2/UpgradeableRegistrarController.sol"; -import {IL2ReverseRegistrar} from "src/L2/interface/IL2ReverseRegistrar.sol"; -import {IReverseRegistrar} from "src/L2/interface/IReverseRegistrar.sol"; -import {Sha3} from "src/lib/Sha3.sol"; -import {BASE_ETH_NODE} from "src/util/Constants.sol"; - -import {BaseSepolia as BaseSepoliaConstants} from "test/Fork/BaseSepoliaConstants.sol"; -import {L2Resolver} from "src/L2/L2Resolver.sol"; -import {ReverseRegistrar} from "src/L2/ReverseRegistrar.sol"; - -contract BaseSepoliaForkBase is Test { - // RPC alias must be configured in foundry.toml as `base-sepolia`. - string internal constant FORK_ALIAS = "base-sepolia"; - - // Addresses from constants - address internal constant REGISTRY = BaseSepoliaConstants.REGISTRY; - address internal constant BASE_REGISTRAR = BaseSepoliaConstants.BASE_REGISTRAR; - address internal constant LEGACY_GA_CONTROLLER = BaseSepoliaConstants.LEGACY_GA_CONTROLLER; - address internal constant LEGACY_L2_RESOLVER = BaseSepoliaConstants.LEGACY_L2_RESOLVER; - address internal constant LEGACY_REVERSE_REGISTRAR = BaseSepoliaConstants.LEGACY_REVERSE_REGISTRAR; - - address internal constant UPGRADEABLE_CONTROLLER_PROXY = BaseSepoliaConstants.UPGRADEABLE_CONTROLLER_PROXY; - address internal constant UPGRADEABLE_L2_RESOLVER_PROXY = BaseSepoliaConstants.UPGRADEABLE_L2_RESOLVER_PROXY; - - // ENS L2 Reverse Registrar (Base Sepolia) - address internal constant ENS_L2_REVERSE_REGISTRAR = BaseSepoliaConstants.ENS_L2_REVERSE_REGISTRAR; - - // Owners / ops - address internal constant L2_OWNER = BaseSepoliaConstants.L2_OWNER; - - // Actors - uint256 internal userPk; - address internal user; - - // Interfaces - RegistrarController internal legacyController; - UpgradeableRegistrarController internal upgradeableController; - NameResolver internal legacyResolver; - IL2ReverseRegistrar internal l2ReverseRegistrar; - - function setUp() public virtual { - vm.createSelectFork(FORK_ALIAS); - - // Create a deterministic EOA we control for signing - userPk = uint256(keccak256("basenames.fork.user")); - user = vm.addr(userPk); - - legacyController = RegistrarController(LEGACY_GA_CONTROLLER); - upgradeableController = UpgradeableRegistrarController(UPGRADEABLE_CONTROLLER_PROXY); - legacyResolver = NameResolver(LEGACY_L2_RESOLVER); - l2ReverseRegistrar = IL2ReverseRegistrar(ENS_L2_REVERSE_REGISTRAR); - } - - function _labelFor(string memory name) internal pure returns (bytes32) { - return keccak256(bytes(name)); - } - - function _nodeFor(string memory name) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(BASE_ETH_NODE, _labelFor(name))); - } - - function _fullName(string memory name) internal pure returns (string memory) { - return string.concat(name, ".base.eth"); - } - - function _baseReverseNode(address addr, bytes32 baseReverseParentNode) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(baseReverseParentNode, Sha3.hexAddress(addr))); - } - - // Build a signature for ENS L2 Reverse Registrar setNameForAddrWithSignature, EIP-191 style - function _buildL2ReverseSignature(string memory fullName, uint256[] memory coinTypes, uint256 expiry) - internal - view - returns (bytes memory) - { - bytes4 selector = IL2ReverseRegistrar.setNameForAddrWithSignature.selector; - bytes32 inner = - keccak256(abi.encodePacked(ENS_L2_REVERSE_REGISTRAR, selector, user, expiry, fullName, coinTypes)); - bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", inner)); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(userPk, digest); - return abi.encodePacked(r, s, v); - } -} diff --git a/test/Fork/ENSIP19DataMigrationsMainnet.t.sol b/test/Fork/ENSIP19DataMigrationsMainnet.t.sol new file mode 100644 index 0000000..5dec524 --- /dev/null +++ b/test/Fork/ENSIP19DataMigrationsMainnet.t.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {BaseMainnetConfig} from "./BaseMainnetConfig.t.sol"; +import {AbstractENSIP19DataMigrations} from "./AbstractENSIP19DataMigrations.t.sol"; + +contract ENSIP19DataMigrationsMainnet is BaseMainnetConfig, AbstractENSIP19DataMigrations {} diff --git a/test/Fork/ENSIP19DataMigrationsSepolia.t.sol b/test/Fork/ENSIP19DataMigrationsSepolia.t.sol new file mode 100644 index 0000000..667a081 --- /dev/null +++ b/test/Fork/ENSIP19DataMigrationsSepolia.t.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {BaseSepoliaConfig} from "./BaseSepoliaConfig.t.sol"; +import {AbstractENSIP19DataMigrations} from "./AbstractENSIP19DataMigrations.t.sol"; + +contract ENSIP19DataMigrationsSepolia is BaseSepoliaConfig, AbstractENSIP19DataMigrations {} diff --git a/test/Fork/ENSIP19LegacyFlowsMainnet.t.sol b/test/Fork/ENSIP19LegacyFlowsMainnet.t.sol new file mode 100644 index 0000000..3a90a97 --- /dev/null +++ b/test/Fork/ENSIP19LegacyFlowsMainnet.t.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {BaseMainnetConfig} from "./BaseMainnetConfig.t.sol"; +import {AbstractENSIP19LegacyFlows} from "./AbstractENSIP19LegacyFlows.t.sol"; + +contract ENSIP19LegacyFlowsMainnet is BaseMainnetConfig, AbstractENSIP19LegacyFlows {} diff --git a/test/Fork/ENSIP19LegacyFlowsSepolia.t.sol b/test/Fork/ENSIP19LegacyFlowsSepolia.t.sol new file mode 100644 index 0000000..44bfe2e --- /dev/null +++ b/test/Fork/ENSIP19LegacyFlowsSepolia.t.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {BaseSepoliaConfig} from "./BaseSepoliaConfig.t.sol"; +import {AbstractENSIP19LegacyFlows} from "./AbstractENSIP19LegacyFlows.t.sol"; + +contract ENSIP19LegacyFlowsSepolia is BaseSepoliaConfig, AbstractENSIP19LegacyFlows {} diff --git a/test/Fork/ENSIP19NewFlowsMainnet.t.sol b/test/Fork/ENSIP19NewFlowsMainnet.t.sol new file mode 100644 index 0000000..a43c8cc --- /dev/null +++ b/test/Fork/ENSIP19NewFlowsMainnet.t.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {BaseMainnetConfig} from "./BaseMainnetConfig.t.sol"; +import {AbstractENSIP19NewFlows} from "./AbstractENSIP19NewFlows.t.sol"; + +contract ENSIP19NewFlowsMainnet is BaseMainnetConfig, AbstractENSIP19NewFlows {} diff --git a/test/Fork/ENSIP19NewFlowsSepolia.t.sol b/test/Fork/ENSIP19NewFlowsSepolia.t.sol new file mode 100644 index 0000000..27e0bfe --- /dev/null +++ b/test/Fork/ENSIP19NewFlowsSepolia.t.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {BaseSepoliaConfig} from "./BaseSepoliaConfig.t.sol"; +import {AbstractENSIP19NewFlows} from "./AbstractENSIP19NewFlows.t.sol"; + +contract ENSIP19NewFlowsSepolia is BaseSepoliaConfig, AbstractENSIP19NewFlows {}