diff --git a/.gitignore b/.gitignore index 7d337b1..6b86845 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ report/ lcov.info* broadcast/ +.DS_Store diff --git a/foundry.toml b/foundry.toml index 0c1c31c..3052c52 100644 --- a/foundry.toml +++ b/foundry.toml @@ -9,9 +9,12 @@ optimizer = true optimizer_runs = 200 # The test suite reads its chain id / CCIP selector table from JSON. Read-only, -# and scoped to that one directory. +# and scoped to that one directory. `./artifacts` is writable so `CreateRepo` +# can drop its per-deployment envelope (`artifacts--.json`) +# for later ingestion into artifacts-hub. fs_permissions = [ { access = "read", path = "./test/fixtures" }, + { access = "write", path = "./artifacts" }, ] # See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options diff --git a/lib/just-foundry b/lib/just-foundry index 3b8e5cb..5537de3 160000 --- a/lib/just-foundry +++ b/lib/just-foundry @@ -1 +1 @@ -Subproject commit 3b8e5cb1dfe3440b8eddd4431d93613cbddf5bce +Subproject commit 5537de3f58f7e8913b03033af5403633d1a4397d diff --git a/script/CreateRepo.sol b/script/CreateRepo.sol index 2550048..1870b0a 100644 --- a/script/CreateRepo.sol +++ b/script/CreateRepo.sol @@ -14,6 +14,12 @@ import { CrossChainController } from "@src/CrossChainController.sol"; /// @title CreateRepo /// @notice Deploys `CrossChainControllerSetup` inside PluginRepoFactory contract CreateRepo is Script { + /// @dev Slug this plugin is registered under in artifacts-hub + /// (`plugins.` in `addresses/.json`). Must match the + /// catalog entry in + /// `artifacts-hub/scripts/lib/plugin-catalog.ts`. + string internal constant PLUGIN_SLUG = "crosschain"; + /// @dev Pinned metadata for the initial build; update whenever a new /// metadata JSON is re-pinned. Sources live in /// `src/{release,build}-metadata.json`; pin them with `just ipfs-pin`. @@ -86,5 +92,77 @@ contract CreateRepo is Script { console.log( "- ENS subdomain: ", bytes(pluginEnsSubdomain).length == 0 ? "(none)" : pluginEnsSubdomain ); + + // Emit the artifacts-hub envelope for later ingestion. Skipped in + // simulations (no NETWORK_NAME wired in and no artifact to keep). + if (!vm.envOr("SIMULATION", false)) { + writeArtifact(); + } + } + + /// @notice Writes `artifacts/artifacts--.json` in the + /// shape defined by `PluginArtifact` in + /// `artifacts-hub/scripts/schema.ts`. The `plugin` subtree matches + /// the AddressBook `Plugin` schema verbatim, so an artifacts-hub + /// ingest step can merge it into `addresses/.json` under + /// `plugins.` without any per-plugin adapter code. + function writeArtifact() internal { + string memory networkName = vm.envString("NETWORK_NAME"); + string memory timestampStr = vm.toString(block.timestamp); + address implementation = IPluginSetup(pluginSetup).implementation(); + + // Skip the `ens` field entirely when the repo was deployed without an + // ENS subdomain, matching the schema's `optional` treatment. + string memory ensLine = bytes(pluginEnsSubdomain).length == 0 + ? "" + : string.concat(" \"ens\": \"", pluginEnsSubdomain, ".plugin.dao.eth\",\n"); + + string memory header = string.concat( + "{\n", + " \"chainId\": ", + vm.toString(block.chainid), + ",\n", + " \"network\": \"", + networkName, + "\",\n", + " \"timestamp\": ", + timestampStr, + ",\n", + " \"slug\": \"", + PLUGIN_SLUG, + "\",\n" + ); + string memory pluginBody = string.concat( + " \"plugin\": {\n", + " \"repo\": \"", + vm.toString(address(myPluginRepo)), + "\",\n", + ensLine, + " \"maintainer\": \"", + vm.toString(managementDao), + "\",\n" + ); + string memory versionsBlock = string.concat( + " \"versions\": [\n", + " {\n", + " \"release\": 1,\n", + " \"build\": 1,\n", + " \"setup\": \"", + vm.toString(pluginSetup), + "\",\n", + " \"implementation\": \"", + vm.toString(implementation), + "\",\n", + " \"current\": true\n", + " }\n", + " ]\n", + " }\n", + "}\n" + ); + + string memory outPath = + string.concat(vm.projectRoot(), "/artifacts/artifacts-", networkName, "-", timestampStr, ".json"); + vm.writeFile(outPath, string.concat(header, pluginBody, versionsBlock)); + console.log("Artifact written to", outPath); } }