packages/solidity-devops/src/base/PathFinder.sol
// 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 {
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");
}
}