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  }