// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; import {StringUtils} from "../libs/StringUtils.sol"; import {CommonBase} from "forge-std/Base.sol"; import {stdJson} from "forge-std/StdJson.sol"; abstract contract PathFinder is CommonBase { using StringUtils for string; using stdJson for string; string private constant DEFAULT_DEVOPS_CONFIG = "./devops.json"; string internal constant ENVIRONMENT_PROD = ""; string private devopsConfig; modifier withDevopsConfig() { require(devopsConfig.length() > 0, "Devops config not loaded"); _; } function assertFileExists(string memory filePath) internal view { require(vm.exists(filePath), StringUtils.concat("File does not exist: ", filePath)); } function loadDevopsConfig() internal { string memory devopsConfigPath = getDevopsConfigPath(); assertFileExists(devopsConfigPath); devopsConfig = vm.readFile(devopsConfigPath); } // ═══════════════════════════════════════════════ PATH GETTERS ════════════════════════════════════════════════════ /// @dev Path to the devops.json file. Could be overridden if the location of the file is different. function getDevopsConfigPath() internal pure virtual returns (string memory) { return DEFAULT_DEVOPS_CONFIG; } /// @notice Returns the path to the directory where the forge artifacts for the contracts are stored. /// @dev The path is configured in the devops.json file. function getForgeArtifactsPath() internal view withDevopsConfig returns (string memory) { return devopsConfig.readString(".forgeArtifacts").concat("/"); } /// @notice Returns the path to the temp directory where the deployment artifacts are saved during a script run. /// Note: deployment artifacts are NOT saved to the deployments directory automatically, another script must be run /// to verify that the deployment was successful and save the deployment artifacts to the deployments directory. /// The reason for this is that the forge script is simulated before the broadcasted transactions are sent, /// and the artifacts are saved during the script simulation. So we can't know if the deployment was successful /// until the script is actually run. /// @dev The path is configured in the devops.json file. function getFreshDeploymentsPath() internal view withDevopsConfig returns (string memory) { return devopsConfig.readString(".freshDeployments").concat("/"); } /// @notice Returns the path to the directory where the deployment artifacts are stored. /// Note: only verified deployments are stored in this directory. /// @dev The path is configured in the devops.json file. function getDeploymentsPath() internal view withDevopsConfig returns (string memory) { return devopsConfig.readString(".deployments").concat("/"); } /// @notice Returns the path to the directory where the deployment configuration files are stored. /// @dev The path is configured in the devops.json file. function getDeployConfigsPath() internal view withDevopsConfig returns (string memory) { return devopsConfig.readString(".deployConfigs").concat("/"); } /// @notice Returns the path to the global deployment configuration file for a contract. /// @dev Override this function to customize the path to the global deployment config file. function getGlobalDeployConfigPath() internal view virtual returns (string memory) { return getDeployConfigsPath().concat("global/"); } // ═════════════════════════════════════════════ FILE NAME GETTERS ═════════════════════════════════════════════════ /// @notice Returns the path to the contract artifact generated by forge. /// Example: "artifacts/SynapseRouter.sol/SynapseRouter.json" function getArtifactFN(string memory contractName) internal view returns (string memory) { return getForgeArtifactsPath().concat(contractName, ".sol/", contractName, ".json"); } /// @notice Returns the path to the FRESH contract deployment JSON for a contract. /// Example: ".deployments/mainnet/SynapseRouter.json" function getFreshDeploymentFN( string memory chain, string memory contractName ) internal view returns (string memory) { return getFreshDeploymentsPath().concat(chain, "/", contractName, ".json"); } /// @notice Returns the path to the SAVED deployment JSON for a contract. /// Example: "deployments/mainnet/SynapseRouter.json" function getDeploymentFN(string memory chain, string memory contractName) internal view returns (string memory) { return getDeploymentsPath().concat(chain, "/", contractName, ".json"); } /// @notice Returns the path to the generic file on a given chain. /// @dev Useful for the files that are not specific to a contract, but are specific to a chain. function getChainGenericFN(string memory chain, string memory fileName) internal view returns (string memory) { return getDeployConfigsPath().concat(chain, "/", fileName); } /// @notice Returns the path to the contract deployment config JSON for a contract on a given chain. /// Example: "script/configs/mainnet/SynapseRouter.dc.json" function getDeployConfigFN(string memory chain, string memory contractName) internal view returns (string memory) { return getChainGenericFN({chain: chain, fileName: contractName.concat(".dc.json")}); } /// @notice Returns the path to the global config JSON that is shared across all chains for a contract. /// We expect different environments to exist, therefore the following pattern is used: /// - For a production environment, the environment param is empty, e.g. "script/configs/global/SynapseCCTP.json" /// - For a testnet, the environment param is "testnet", e.g. "script/configs/global/testnet/SynapseCCTP.json" function getGlobalDeployConfigFN( string memory contractName, string memory environment ) internal view returns (string memory) { string memory environmentDir = environment.equals(ENVIRONMENT_PROD) ? "" : environment.concat("/"); return getGlobalDeployConfigPath().concat(environmentDir, contractName, ".json"); } }