diff --git a/.env.example b/.env.example index a25df21..9f884ba 100644 --- a/.env.example +++ b/.env.example @@ -26,8 +26,9 @@ # The maintainer defaults to MANAGEMENT_DAO_ADDRESS from the active # just-foundry network config; override it here for a non-standard maintainer. # MANAGEMENT_DAO_ADDRESS= -RELEASE_METADATA_URI= -BUILD_METADATA_URI= +# RELEASE_METADATA_URI="ipfs://QmSfiCe5sCkrbA7gw6xriqCVx8iR1C2eAqL1iWYp9HbDAV" +# BUILD_METADATA_URI="ipfs://QmZuSnnzNFA9Zw2Vzb1KgaxCqox5uzYBR3UUhbef3FoUzy" -# Optional: a random subdomain is used if empty -# PLUGIN_ENS_SUBDOMAIN= +# Optional. If empty, ENS registration is skipped — the repo is still deployed +# and registered on the PluginRepoRegistry, it just has no ENS name. +PLUGIN_ENS_SUBDOMAIN=cross-chain-controller diff --git a/.vars.yaml b/.vars.yaml index 4ca0b3e..703f1b7 100644 --- a/.vars.yaml +++ b/.vars.yaml @@ -9,6 +9,7 @@ keys: - DEPLOYER_KEY - ETHERSCAN_API_KEY - RPC_URL # optional override: the public RPC from the network file + # - PINATA_JWT # - REFUND_ADDRESS # optional: burner wallet refund target # Profiles are keyed by network name — just switch activates the matching profile. diff --git a/justfile b/justfile index 47d13c4..c5a2700 100644 --- a/justfile +++ b/justfile @@ -33,3 +33,27 @@ test-fork *args: BUILD_PARAMS=$(just resolve-build-params) || exit 1 $FORGE test $BUILD_PARAMS -vvv \ --match-path 'test/e2e/fork/*' {{ args }} + +# Deploy the full CCIP lane on Arbitrum Sepolia + Base Sepolia in one run. +# `script/testnet/Test_Deploy.s.sol` forks both chains internally, so this +# bypasses the active just-foundry network. Needs ARBITRUM_SEPOLIA_RPC, +# BASE_SEPOLIA_RPC and DEPLOYER_KEY in `.env`. Contracts are not verified — +# use `forge verify-contract` per chain if you need it. +[group('script')] +deploy-testnet *args: + #!/usr/bin/env bash + set -euo pipefail + [ -f .env ] && set -a && source .env && set +a + for v in DEPLOYER_KEY ARBITRUM_SEPOLIA_RPC BASE_SEPOLIA_RPC; do + if [ -z "${!v:-}" ]; then + echo "$v must be set (in .env or the environment)." + exit 1 + fi + done + source {{ JUST_LIB }} + mkdir -p logs + LOG="logs/Test_Deploy-$(date +%y-%m-%d-%H-%M).log" + CMD=(forge script script/testnet/Test_Deploy.s.sol:Test_Deploy \ + --sig "run()" --broadcast --multi -vvv {{ args }}) + run_logged "$LOG" "${CMD[@]}" + echo "Log: $LOG" diff --git a/script/CreateRepo.sol b/script/CreateRepo.sol index 797e465..2550048 100644 --- a/script/CreateRepo.sol +++ b/script/CreateRepo.sol @@ -14,6 +14,13 @@ import { CrossChainController } from "@src/CrossChainController.sol"; /// @title CreateRepo /// @notice Deploys `CrossChainControllerSetup` inside PluginRepoFactory contract CreateRepo is Script { + /// @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`. + /// Overridable via `RELEASE_METADATA_URI` / `BUILD_METADATA_URI` in `.env`. + string internal constant DEFAULT_RELEASE_METADATA_URI = "ipfs://QmSfiCe5sCkrbA7gw6xriqCVx8iR1C2eAqL1iWYp9HbDAV"; + string internal constant DEFAULT_BUILD_METADATA_URI = "ipfs://QmZuSnnzNFA9Zw2Vzb1KgaxCqox5uzYBR3UUhbef3FoUzy"; + address deployer; string pluginEnsSubdomain; address managementDao; @@ -48,22 +55,19 @@ contract CreateRepo is Script { pluginRepoFactory = PluginRepoFactory(vm.envAddress("PLUGIN_REPO_FACTORY_ADDRESS")); vm.label(address(pluginRepoFactory), "PluginRepoFactory"); - // Read the rest of environment variables + // Optional: an empty subdomain skips ENS registration entirely. The + // repo is still deployed and registered on the `PluginRepoRegistry`, + // it just has no ENS name. pluginEnsSubdomain = vm.envOr("PLUGIN_ENS_SUBDOMAIN", string("")); - // Using a random subdomain if empty - if (bytes(pluginEnsSubdomain).length == 0) { - pluginEnsSubdomain = string.concat("cross-chain-controller", vm.toString(block.timestamp)); - } - // The Aragon management DAO becomes the repo maintainer. // `MANAGEMENT_DAO_ADDRESS` is supplied by the active just-foundry // network config; override in `.env` for a non-standard maintainer. managementDao = vm.envAddress("MANAGEMENT_DAO_ADDRESS"); vm.label(managementDao, "Maintainer"); - releaseMetadataUri = vm.envOr("RELEASE_METADATA_URI", bytes(" ")); - buildMetadataUri = vm.envOr("BUILD_METADATA_URI", bytes(" ")); + releaseMetadataUri = vm.envOr("RELEASE_METADATA_URI", bytes(DEFAULT_RELEASE_METADATA_URI)); + buildMetadataUri = vm.envOr("BUILD_METADATA_URI", bytes(DEFAULT_BUILD_METADATA_URI)); } function run() public broadcast { @@ -79,6 +83,8 @@ contract CreateRepo is Script { console.log("- PluginSetup: ", pluginSetup); console.log("- Implementation: ", IPluginSetup(pluginSetup).implementation()); console.log("- Maintainer (Management DAO): ", managementDao); - console.log("- ENS subdomain: ", pluginEnsSubdomain); + console.log( + "- ENS subdomain: ", bytes(pluginEnsSubdomain).length == 0 ? "(none)" : pluginEnsSubdomain + ); } } diff --git a/src/metadata/build-metadata.json b/src/metadata/build-metadata.json new file mode 100644 index 0000000..d239c1b --- /dev/null +++ b/src/metadata/build-metadata.json @@ -0,0 +1,33 @@ +{ + "ui": {}, + "change": "Initial build.", + "pluginSetup": { + "prepareInstallation": { + "description": "The information required for the installation of build 1.", + "inputs": [ + { + "name": "executor", + "type": "address", + "internalType": "address", + "description": "The executor that inbound cross-chain payloads run on. Pass address(0) to have the setup deploy a dedicated Executor owned by the plugin. Pass the DAO itself to keep execution on the DAO (the setup will grant EXECUTE_PERMISSION on the DAO to the plugin). Any other contract is taken as-is: the DAO must separately authorize the plugin to call `execute` on it, or the receive path cannot execute." + }, + { + "name": "guardian", + "type": "address", + "internalType": "address", + "description": "An address granted PAUSE_PERMISSION only, so it can freeze the message paths (forward / receive / retry) but not reopen them. Pass address(0) for none." + }, + { + "name": "minFailedMessageGas", + "type": "uint256", + "internalType": "uint256", + "description": "Gas the controller withholds so a failed inbound message can always be recorded as Delivered and stay retryable/cancellable. 45000 is a good default; 0 disables the reserve." + } + ] + }, + "prepareUninstallation": { + "description": "No input is required for the uninstallation.", + "inputs": [] + } + } +} diff --git a/src/metadata/release-metadata.json b/src/metadata/release-metadata.json new file mode 100644 index 0000000..d246bb3 --- /dev/null +++ b/src/metadata/release-metadata.json @@ -0,0 +1,5 @@ +{ + "name": "Cross-Chain Controller", + "description": "An Aragon OSx plugin that lets a DAO execute Action[] payloads on another chain via a bridge adapter.", + "images": {} +}