diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 729e38f6c..70c82990b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -259,6 +259,16 @@ jobs: echo "No Solidity files to lint with Forge" fi + - name: Check OpenZeppelin v3 alias scope + run: | + # The @openzeppelin/contracts-v3 alias (SafeMath for 0.7.6 code) is only for graph-core + MATCHES=$(git grep -l '@openzeppelin/contracts-v3' -- '*.sol' ':!packages/graph-core/**') || [ $? -eq 1 ] + if [ -n "$MATCHES" ]; then + echo "@openzeppelin/contracts-v3 may only be imported from packages/graph-core:" + echo "$MATCHES" + exit 1 + fi + - name: Check lint results if: always() run: | diff --git a/packages/contracts/contracts/epochs/EpochManager.sol b/packages/graph-core/contracts/epochs/EpochManager.sol similarity index 94% rename from packages/contracts/contracts/epochs/EpochManager.sol rename to packages/graph-core/contracts/epochs/EpochManager.sol index 2e3033d4f..771e67ae0 100644 --- a/packages/contracts/contracts/epochs/EpochManager.sol +++ b/packages/graph-core/contracts/epochs/EpochManager.sol @@ -5,10 +5,10 @@ pragma solidity ^0.7.6; // TODO: Re-enable and fix issues when publishing a new version // solhint-disable gas-indexed-events, gas-small-strings, gas-strict-inequalities -import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; +import { SafeMath } from "@openzeppelin/contracts-v3/math/SafeMath.sol"; -import { GraphUpgradeable } from "@graphprotocol/graph-core/contracts/upgrades/GraphUpgradeable.sol"; -import { Managed } from "@graphprotocol/graph-core/contracts/governance/Managed.sol"; +import { GraphUpgradeable } from "../upgrades/GraphUpgradeable.sol"; +import { Managed } from "../governance/Managed.sol"; import { EpochManagerV1Storage } from "./EpochManagerStorage.sol"; import { IEpochManager } from "@graphprotocol/interfaces/contracts/contracts/epochs/IEpochManager.sol"; diff --git a/packages/contracts/contracts/epochs/EpochManagerStorage.sol b/packages/graph-core/contracts/epochs/EpochManagerStorage.sol similarity index 87% rename from packages/contracts/contracts/epochs/EpochManagerStorage.sol rename to packages/graph-core/contracts/epochs/EpochManagerStorage.sol index 3c3d8bdba..894f34a46 100644 --- a/packages/contracts/contracts/epochs/EpochManagerStorage.sol +++ b/packages/graph-core/contracts/epochs/EpochManagerStorage.sol @@ -2,7 +2,7 @@ pragma solidity ^0.7.6; -import { Managed } from "@graphprotocol/graph-core/contracts/governance/Managed.sol"; +import { Managed } from "../governance/Managed.sol"; /** * @title Epoch Manager Storage V1 diff --git a/packages/graph-core/hardhat.config.ts b/packages/graph-core/hardhat.config.ts index e974652ed..b0b396689 100644 --- a/packages/graph-core/hardhat.config.ts +++ b/packages/graph-core/hardhat.config.ts @@ -61,6 +61,9 @@ const config: HardhatUserConfig = { '@openzeppelin/contracts/**/*': { default: 'off', }, + '@openzeppelin/contracts-v3/**/*': { + default: 'off', + }, }, } diff --git a/packages/graph-core/package.json b/packages/graph-core/package.json index 21955e65d..2adfb95d0 100644 --- a/packages/graph-core/package.json +++ b/packages/graph-core/package.json @@ -27,7 +27,8 @@ }, "dependencies": { "@graphprotocol/interfaces": "workspace:^", - "@openzeppelin/contracts": "^5.4.0" + "@openzeppelin/contracts": "^5.4.0", + "@openzeppelin/contracts-v3": "npm:@openzeppelin/contracts@3.4.2" }, "devDependencies": { "@ethersproject/abi": "^5.8.0", diff --git a/packages/horizon/test/unit/epochs/EpochManager.t.sol b/packages/graph-core/test/unit/epochs/EpochManager.t.sol similarity index 91% rename from packages/horizon/test/unit/epochs/EpochManager.t.sol rename to packages/graph-core/test/unit/epochs/EpochManager.t.sol index 6b21b8ef3..4afd9bdcb 100644 --- a/packages/horizon/test/unit/epochs/EpochManager.t.sol +++ b/packages/graph-core/test/unit/epochs/EpochManager.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.27; import { IEpochManagerLike } from "./IEpochManagerLike.sol"; +import { VmSafe } from "forge-std/Vm.sol"; import { ProtocolFixture } from "../shared/ProtocolFixture.t.sol"; contract EpochManagerTest is ProtocolFixture { @@ -17,7 +18,7 @@ contract EpochManagerTest is ProtocolFixture { function setUp() public { vm.warp(1_700_000_000); _deployProtocolBase(); - address impl = _deployArtifact(string.concat(PKG_ARTIFACTS, "epochs/EpochManager.sol/EpochManager.json"), ""); + address impl = _deployPkg("EpochManager.sol:EpochManager", ""); epochManager = IEpochManagerLike( _deployBehindProxy( impl, @@ -26,6 +27,15 @@ contract EpochManagerTest is ProtocolFixture { ); } + function test_Bytecode_FoundryMatchesHardhat() public { + vm.skip(vm.isContext(VmSafe.ForgeContext.Coverage)); + string memory json = vm.readFile("artifacts/contracts/epochs/EpochManager.sol/EpochManager.json"); + bytes memory hardhat = _stripMetadata(vm.parseJsonBytes(json, ".bytecode")); + bytes memory foundry = _stripMetadata(vm.getCode("EpochManager.sol:EpochManager")); + assertGt(hardhat.length, 0); + assertEq(foundry, hardhat); + } + modifier withLifecycleLength() { vm.prank(governor); epochManager.setEpochLength(EPOCH_LENGTH); diff --git a/packages/horizon/test/unit/epochs/IEpochManagerLike.sol b/packages/graph-core/test/unit/epochs/IEpochManagerLike.sol similarity index 100% rename from packages/horizon/test/unit/epochs/IEpochManagerLike.sol rename to packages/graph-core/test/unit/epochs/IEpochManagerLike.sol diff --git a/packages/graph-core/test/unit/shared/Fixture.t.sol b/packages/graph-core/test/unit/shared/Fixture.t.sol index c3e3a0388..6286e2a7c 100644 --- a/packages/graph-core/test/unit/shared/Fixture.t.sol +++ b/packages/graph-core/test/unit/shared/Fixture.t.sol @@ -28,13 +28,6 @@ contract FixtureTest is GraphCoreTest { assertEq(foundry, hardhat); } - function _stripMetadata(bytes memory code) internal pure returns (bytes memory out) { - uint256 metadataLength = (uint256(uint8(code[code.length - 2])) << 8) | uint256(uint8(code[code.length - 1])); - uint256 newLength = code.length - metadataLength - 2; - out = new bytes(newLength); - for (uint256 i = 0; i < newLength; i++) out[i] = code[i]; - } - function test_Fixture_ProxyWiredToImplementation() public view { IGraphProxy proxy = IGraphProxy(address(managed)); assertEq(proxyAdmin.getProxyAdmin(proxy), address(proxyAdmin)); diff --git a/packages/graph-core/test/unit/shared/ProtocolFixture.t.sol b/packages/graph-core/test/unit/shared/ProtocolFixture.t.sol index f34f5e83e..e4863846f 100644 --- a/packages/graph-core/test/unit/shared/ProtocolFixture.t.sol +++ b/packages/graph-core/test/unit/shared/ProtocolFixture.t.sol @@ -44,4 +44,11 @@ abstract contract ProtocolFixture is Test { vm.prank(governor); controller.setContractProxy(keccak256(bytes(name)), addr); } + + function _stripMetadata(bytes memory code) internal pure returns (bytes memory out) { + uint256 metadataLength = (uint256(uint8(code[code.length - 2])) << 8) | uint256(uint8(code[code.length - 1])); + uint256 newLength = code.length - metadataLength - 2; + out = new bytes(newLength); + for (uint256 i = 0; i < newLength; i++) out[i] = code[i]; + } } diff --git a/packages/horizon/foundry.toml b/packages/horizon/foundry.toml index b3e1c7054..088193a98 100644 --- a/packages/horizon/foundry.toml +++ b/packages/horizon/foundry.toml @@ -5,7 +5,7 @@ libs = ["node_modules"] auto_detect_remappings = false test = 'test' cache_path = 'cache_forge' -fs_permissions = [{ access = "read", path = "./" }, { access = "read", path = "node_modules/@graphprotocol/contracts/artifacts" }, { access = "read", path = "node_modules/@graphprotocol/graph-core/artifacts" }] +fs_permissions = [{ access = "read", path = "./" }, { access = "read", path = "node_modules/@graphprotocol/graph-core/artifacts" }] solc_version = '0.8.35' evm_version = 'cancun' # Suppress solc warnings emitted from third-party code we don't control diff --git a/packages/horizon/test/unit/shared/ProtocolFixture.t.sol b/packages/horizon/test/unit/shared/ProtocolFixture.t.sol index e1567eaa9..561f83032 100644 --- a/packages/horizon/test/unit/shared/ProtocolFixture.t.sol +++ b/packages/horizon/test/unit/shared/ProtocolFixture.t.sol @@ -8,7 +8,6 @@ import { IGraphProxyAdmin } from "@graphprotocol/interfaces/contracts/contracts/ abstract contract ProtocolFixture is Test { string internal constant CORE_ARTIFACTS = "node_modules/@graphprotocol/graph-core/artifacts/contracts/"; - string internal constant PKG_ARTIFACTS = "node_modules/@graphprotocol/contracts/artifacts/contracts/"; address internal governor; // makeAddr("governor"), set in _deployProtocolBase IController internal controller; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b59b38c75..be105f5d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -583,6 +583,9 @@ importers: '@openzeppelin/contracts': specifier: ^5.4.0 version: 5.4.0 + '@openzeppelin/contracts-v3': + specifier: npm:@openzeppelin/contracts@3.4.2 + version: '@openzeppelin/contracts@3.4.2' devDependencies: '@ethersproject/abi': specifier: ^5.8.0 diff --git a/scripts/contracts-migration/manifest.json b/scripts/contracts-migration/manifest.json index 7b3059b47..5c5741093 100644 --- a/scripts/contracts-migration/manifest.json +++ b/scripts/contracts-migration/manifest.json @@ -12,7 +12,7 @@ "GraphCurationToken": "packages/graph-token/artifacts/contracts/curation/GraphCurationToken.sol/GraphCurationToken.json", "SubgraphNFT": "packages/graph-token/artifacts/contracts/discovery/SubgraphNFT.sol/SubgraphNFT.json", "SubgraphNFTDescriptor": "packages/graph-token/artifacts/contracts/discovery/SubgraphNFTDescriptor.sol/SubgraphNFTDescriptor.json", - "EpochManager": "packages/contracts/artifacts/contracts/epochs/EpochManager.sol/EpochManager.json", + "EpochManager": "packages/graph-core/artifacts/contracts/epochs/EpochManager.sol/EpochManager.json", "RewardsManager": "packages/contracts/artifacts/contracts/rewards/RewardsManager.sol/RewardsManager.json", "HorizonStaking": "packages/horizon/build/contracts/contracts/staking/HorizonStaking.sol/HorizonStaking.json", "GraphPayments": "packages/horizon/build/contracts/contracts/payments/GraphPayments.sol/GraphPayments.json",