github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/scripts/SemverLock.s.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity 0.8.15; 3 4 import { Script } from "forge-std/Script.sol"; 5 import { stdJson } from "forge-std/StdJson.sol"; 6 import { console2 as console } from "forge-std/console2.sol"; 7 8 contract SemverLock is Script { 9 function run() public { 10 // First, find all contracts with a Semver inheritance. 11 string[] memory commands = new string[](3); 12 commands[0] = "bash"; 13 commands[1] = "-c"; 14 commands[2] = "grep -rl '@custom:semver' src | jq -Rs 'split(\"\\n\") | map(select(length > 0))'"; 15 string memory rawFiles = string(vm.ffi(commands)); 16 17 string[] memory files = vm.parseJsonStringArray(rawFiles, ""); 18 writeSemverLock(files); 19 } 20 21 /// @dev Writes a Semver lockfile 22 function writeSemverLock(string[] memory _files) internal { 23 string memory out; 24 for (uint256 i; i < _files.length; i++) { 25 // Use FFI to read the file to remove the need for FS permissions in the foundry.toml. 26 string[] memory commands = new string[](2); 27 commands[0] = "cat"; 28 commands[1] = _files[i]; 29 string memory fileContents = string(vm.ffi(commands)); 30 31 // Grab the contract name 32 commands = new string[](3); 33 commands[0] = "bash"; 34 commands[1] = "-c"; 35 commands[2] = string.concat("echo \"", _files[i], "\"| sed -E \'s|src/.*/(.+)\\.sol|\\1|\'"); 36 string memory contractName = string(vm.ffi(commands)); 37 38 commands[2] = "forge config --json | jq -r .out"; 39 string memory artifactsDir = string(vm.ffi(commands)); 40 41 // Handle the case where there are multiple artifacts for a contract. This happens 42 // when the same contract is compiled with multiple compiler versions. 43 string memory contractArtifactDir = string.concat(artifactsDir, "/", contractName, ".sol"); 44 commands[2] = string.concat( 45 "ls -1 --color=never ", contractArtifactDir, " | jq -R -s -c 'split(\"\n\") | map(select(length > 0))'" 46 ); 47 string memory artifactFiles = string(vm.ffi(commands)); 48 49 string[] memory files = stdJson.readStringArray(artifactFiles, ""); 50 require(files.length > 0, string.concat("No artifacts found for ", contractName)); 51 string memory fileName = files[0]; 52 53 // Parse the artifact to get the contract's initcode hash. 54 bytes memory initCode = vm.getCode(string.concat(artifactsDir, "/", contractName, ".sol/", fileName)); 55 56 // Serialize the initcode hash + sourcecode hash in JSON. 57 vm.serializeBytes32(_files[i], "initCodeHash", keccak256(initCode)); 58 string memory obj = vm.serializeBytes32(_files[i], "sourceCodeHash", keccak256(bytes(fileContents))); 59 60 // Serialize the map from the file name -> initcode hash + sourcecode hash in JSON. 61 out = vm.serializeString("", _files[i], obj); 62 } 63 64 // Write the semver lockfile. 65 vm.writeJson(out, "semver-lock.json"); 66 console.logString("Wrote semver lock file to \"semver-lock.json\"."); 67 } 68 }