From e43cf30032fc2b0414f265254657ee4b874bd2be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8r=E2=88=82=C2=A1?= Date: Mon, 13 Jul 2026 15:14:16 +0000 Subject: [PATCH] Improved onboarding flow with just-foundry --- .env.example | 32 ++-- .gitignore | 6 +- .gitmodules | 9 +- Makefile | 28 ---- README.md | 217 +++++++++++++++----------- foundry.lock | 11 +- justfile | 23 +++ lib/buffer | 1 + lib/foundry-env | 1 - lib/just-foundry | 1 + lib/osx | 2 +- lib/osx-commons | 1 - remappings.txt | 5 +- script/DeployDaoWithPlugins.s.sol | 2 +- script/DeploySimple.s.sol | 2 +- script/DeployViaFactory.s.sol | 2 +- script/verify-contracts.sh | 237 ----------------------------- src/MyCloneablePlugin.sol | 2 +- src/MyStaticPlugin.sol | 2 +- src/MyUpgradeablePlugin.sol | 2 +- src/factory/DeploymentFactory.sol | 4 +- src/setup/MyPluginSetup.sol | 6 +- test/MyPlugin.t.sol | 2 +- test/builders/SimpleBuilder.sol | 2 +- test/fork-tests/MyPluginFork.t.sol | 2 +- 25 files changed, 213 insertions(+), 389 deletions(-) delete mode 100644 Makefile create mode 100644 justfile create mode 160000 lib/buffer delete mode 160000 lib/foundry-env create mode 160000 lib/just-foundry delete mode 160000 lib/osx-commons delete mode 100644 script/verify-contracts.sh diff --git a/.env.example b/.env.example index 0687094..c579d1f 100644 --- a/.env.example +++ b/.env.example @@ -1,20 +1,34 @@ -# REQUIRED +# SECRETS (supply locally, never commit — also configurable via `vars`) # --------------------------------------------------- -DEPLOYMENT_PRIVATE_KEY="0x..." +DEPLOYER_KEY="0x..." ETHERSCAN_API_KEY="" # OPTIONAL # --------------------------------------------------- -# If the network's RPC_URL uses an Alchemy endpoint -# ALCHEMY_API_KEY= +# Burner wallet: destination for `just refund` +# REFUND_ADDRESS="0x..." -# If using a burner wallet to deploy -# REFUND_ADDRESS= - -# If running fork tests on a certain block +# Pin fork tests to a specific block # FORK_BLOCK_NUMBER= +# PLUGIN SETTINGS (read by the deploy scripts under script/) +# --------------------------------------------------- + +# Required by DeploySimple: address that maintains the published plugin repo +PLUGIN_REPO_MAINTAINER_ADDRESS="0x..." + +# ENS subdomain for the plugin repo (optional) +# PLUGIN_ENS_SUBDOMAIN="my-plugin" + +# Used by DeployDaoWithPlugins / DeployViaFactory (optional) +# DAO_ENS_SUBDOMAIN="my-dao" +# DAO_METADATA_URI="ipfs://..." -# YOUR CUSTOM SETTINGS +# NETWORK CONFIG # --------------------------------------------------- +# RPC_URL, CHAIN_ID, VERIFIER and the Aragon OSx addresses come from the active +# network in lib/just-foundry/networks/.env — select it with +# `just init ` or `just switch `, and inspect it with `just env`. +# To override a value for one network: `just switch override`, +# then edit the generated .env. file at the repo root. diff --git a/.gitignore b/.gitignore index f155a72..758b28d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,9 +2,13 @@ cache coverage out +artifacts +logs # Files -*.env +.env +.env.* +!.env.example *.log .DS_Store lcov.info diff --git a/.gitmodules b/.gitmodules index 776d929..faca183 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,6 @@ [submodule "lib/osx"] path = lib/osx url = https://github.com/aragon/osx -[submodule "lib/osx-commons"] - path = lib/osx-commons - url = https://github.com/aragon/osx-commons [submodule "lib/ens-contracts"] path = lib/ens-contracts url = https://github.com/ensdomains/ens-contracts @@ -19,6 +16,6 @@ [submodule "lib/buffer"] path = lib/buffer url = https://github.com/ensdomains/buffer -[submodule "lib/foundry-env"] - path = lib/foundry-env - url = https://github.com/aragon/foundry-env.git +[submodule "lib/just-foundry"] + path = lib/just-foundry + url = https://github.com/aragon/just-foundry.git diff --git a/Makefile b/Makefile deleted file mode 100644 index f01eab2..0000000 --- a/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# NOTE: Choose the appropriate deployment script -DEPLOYMENT_SCRIPT ?= DeploySimple -# DEPLOYMENT_SCRIPT ?= DeployDaoWithPlugins -# DEPLOYMENT_SCRIPT ?= DeployViaFactory - -# .env is imported by base.mk -include lib/foundry-env/base.mk - -# - -VERIFY_CONTRACTS_SCRIPT := script/verify-contracts.sh - -## Verification: - -.PHONY: verify-etherscan -verify-etherscan: broadcast/Deploy.s.sol/$(CHAIN_ID)/run-latest.json ## Verify the last deployment on an Etherscan (compatible) explorer - forge build $(FORGE_BUILD_CUSTOM_PARAMS) - bash $(VERIFY_CONTRACTS_SCRIPT) $(CHAIN_ID) $(VERIFIER) $(VERIFIER_URL) $(VERIFIER_API_KEY) - -.PHONY: verify-blockscout -verify-blockscout: broadcast/Deploy.s.sol/$(CHAIN_ID)/run-latest.json ## Verify the last deployment on BlockScout - forge build $(FORGE_BUILD_CUSTOM_PARAMS) - bash $(VERIFY_CONTRACTS_SCRIPT) $(CHAIN_ID) $(VERIFIER) "https://$(BLOCKSCOUT_HOST_NAME)/api" $(VERIFIER_API_KEY) - -.PHONY: verify-sourcify -verify-sourcify: broadcast/Deploy.s.sol/$(CHAIN_ID)/run-latest.json ## Verify the last deployment on Sourcify - forge build $(FORGE_BUILD_CUSTOM_PARAMS) - bash $(VERIFY_CONTRACTS_SCRIPT) $(CHAIN_ID) $(VERIFIER) "" "" diff --git a/README.md b/README.md index 6f6722a..73f7901 100644 --- a/README.md +++ b/README.md @@ -11,40 +11,46 @@ This template is designed to help get developers up and running with OSx in a fe - **Deployment scripts and factories**: Starter scripts for simple plugin publishing, as well as for custom DAO deployments. - **Flexible testing environment**: A set of tools to run unit tests, fork tests, describe use cases and prepare entire deployments in one line. - **Multi explorer code verification**: Verify on multiple block explorers given the same deployment -- **Streamlined action runner**: A self documenting [makefile](#using-the-makefile) to manage the entire workflow +- **Streamlined action runner**: A self documenting [justfile](#using-just) (via [just-foundry](https://github.com/aragon/just-foundry)) to manage the entire workflow - **Code snippets and examples** ## Prerequisites 📋 - [Foundry](https://getfoundry.sh/) - [Git](https://git-scm.com/) -- [Make](https://www.gnu.org/software/make/) +- [just](https://just.systems/) (the command runner). Install it with your package manager (`brew install just`, `cargo install just`, `apt install just`, …) or the standalone script: + ```sh + curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to ~/.local/bin + ``` Optional: - [Docker](https://www.docker.com) (recommended for deploying) -- [Deno](https://deno.land) (used to scaffold the test files) +- [vars](https://github.com/vars-cli/vars) (recommended secrets manager, install with `just install-vars`) ## Getting Started 🏁 [Click here](https://github.com/new?template_name=osx-plugin-template-foundry&template_owner=aragon) to create a repository from the template. -Clone your new repository and initialize it: +Clone your new repository (with submodules) and initialize it: ```bash -git clone git@github.com:/my-plugin +git clone --recurse-submodules git@github.com:/my-plugin cd my-plugin -# Initialize the repo -cp .env.example .env -make init +# Initialize the repo: fetch submodules, scaffold .env, select the network +just init ``` -Edit `.env` to match your desired network and settings. +`just init` fetches the git submodules, copies `.env.example` to `.env` (if missing) and selects a network (`mainnet` by default). Pass another network to target it, e.g. `just init sepolia`. + +Then edit `.env` with your secrets (`DEPLOYER_KEY`, `ETHERSCAN_API_KEY`, …) and settings. Run `just env` to see the fully resolved environment. + +> If you cloned without `--recurse-submodules`, run `git submodule update --init --recursive` first, then `just init`. The `justfile` imports its recipes from `lib/just-foundry/`, so that submodule needs to exist before `just` can run. ### Installing dependencies ```sh -forge install / # replace accordingly +git submodule add / lib/ # replace accordingly # Use the version you need cd lib/ @@ -53,13 +59,13 @@ git checkout v1.9.0 # Commit the version to use cd - git add lib/ -git commit -m"Using repo-name v1.9.0" +git commit -m "Using repo-name v1.9.0" ``` Add the new package to `remappings.txt`: ```txt -@organiation/repo-name/=lib/repo-name +@organization/repo-name/=lib/repo-name/ ``` Verify the status: @@ -68,43 +74,70 @@ Verify the status: git submodule status ``` -### Using the Makefile +### Integrating a governance plugin -The `Makefile` is the target launcher of the project. It's the recommended way to operate the repository. It manages the env variables of common tasks and executes only the steps that need to be run. +To build on top of an existing Aragon governance plugin, add it as a submodule and its remapping. For example, the Multisig plugin: +```sh +git submodule add https://github.com/aragon/multisig-plugin lib/multisig-plugin ``` -$ make -Available recipes: - - make init Check the dependencies and prompt to install if needed - make clean Clean the build artifacts - -Testing lifecycle: - - make test Run unit tests, locally - make test-fork Run fork tests, using RPC_URL - make test-coverage Generate an HTML coverage report under ./report -Deployment targets: - - make predeploy Simulate a protocol deployment - make deploy Deploy the protocol, verify the source code and write to ./artifacts - make resume Retry pending deployment transactions, verify the code and write to ./artifacts +```txt +# remappings.txt +@aragon/multisig-plugin/=lib/multisig-plugin/packages/contracts/src/ +``` -Verification: +```solidity +import {Multisig} from "@aragon/multisig-plugin/Multisig.sol"; +``` - make verify-etherscan Verify the last deployment on an Etherscan (compatible) explorer - make verify-blockscout Verify the last deployment on BlockScout - make verify-sourcify Verify the last deployment on Sourcify +The same pattern applies to other plugins, e.g. `@aragon/token-voting-plugin/=lib/token-voting-plugin/src/`. -Other: +### Using just - make storage-info Show the storage layout of a contract - make refund Refund the remaining balance left on the deployment account +The `justfile` is the target launcher of the project. It's the recommended way to operate the repository: it manages the env variables of common tasks and selects the right flags per network. Run `just` (or `just help`) to list the recipes: - make help Show the main recipes +``` +$ just +Available recipes: + default + help # Show available commands + + [setup] + init network="mainnet" # Fetch submodules, scaffold .env and select the network (default: mainnet) + switch network override="" # Select the active network (pass "override" to create a local editable copy) + setup # Install Foundry + + [script] + predeploy # Dry-run the deploy script (no broadcast) + deploy *args # Deploy: run tests then broadcast (logs to logs/--.log) + + [script-base] + run script *args # Broadcast a forge script — log name is derived from the contract name (or filename) + dry-run script # Simulate running a forge script (no broadcast) + + [test] + test *args # Run all unit tests + test-fork *args # Run fork tests (requires RPC_URL) + test-coverage # Generate an HTML coverage report under ./report + + [helpers] + env # Show current environment (resolved values + sources) + ipfs-pin file # Pin a file to IPFS via Pinata (requires PINATA_JWT in vars or .env) + balance # Show current wallet balance + + [develop] + clean # Clean compiler artifacts and coverage reports + storage-info contract # Show the storage layout of a contract + check-upgrade from to # Check storage layout upgrade compatibility between two contracts + anvil # Start a forked EVM (set FORK_BLOCK_NUMBER in .env to pin a block) + + [verification] + verify type="" script="" # Verify all contracts from the latest broadcast (type: etherscan|blockscout|sourcify) ``` +Networks are defined under `lib/just-foundry/networks/`. Switch with `just switch `; inspect the resolved values with `just env`. See the [just-foundry README](https://github.com/aragon/just-foundry) for the full environment model and secret management with `vars`. + ## Template Variants 🌈 In order to accommodate a wide range of cases, this repo provides comprehensive examples for the following variants: @@ -125,7 +158,7 @@ For upgradeable plugins, consider inheriting from `PluginUpgradeableSetup` inste - [Deploying a DAO with plugin(s) installed](./script/DeployDaoWithPlugins.s.sol) (trusted) - [Deploying a DAO with plugin(s) via a Factory](./script/DeployViaFactory.s.sol) (trustless) -Update `DEPLOYMENT_SCRIPT` in `Makefile` to make it use the deployment script of your choice. +Set `DEPLOY_SCRIPT` in the root `justfile` to the deployment script of your choice (it defaults to `DeploySimple`). ### DAO builders (for testing) @@ -139,37 +172,36 @@ Update `DEPLOYMENT_SCRIPT` in `Makefile` to make it use the deployment script of ## Testing 🔍 -Using `make`: +Using `just`: ``` -$ make +$ just [...] -Testing lifecycle: - -- make test Run unit tests, locally -- make test-fork Run fork tests, using RPC_URL -- make test-coverage Generate an HTML coverage report under ./report + [test] + test *args # Run all unit tests + test-fork *args # Run fork tests (requires RPC_URL) + test-coverage # Generate an HTML coverage report under ./report ``` -Run `make test` or `make test-fork` to check the logic's accordance to the specs. The latter will require `RPC_URL` to be defined. +Run `just test` or `just test-fork` to check the logic's accordance to the specs. The latter will require `RPC_URL` to be defined (it comes from the active network, or set it in `.env`). ### Testing with a local OSx You can deploy an in-memory, local OSx deployment to run your E2E tests on top of it. ```sh -forge install aragon/protocol-factory +git submodule add https://github.com/aragon/protocol-factory lib/protocol-factory ``` You may need to set `via_ir` to `true` on `foundry.toml`. -Given that this repository already depends on OSx, you may want to replace the existing `remappings.txt` entry and use the OSx path provided by `protocol-factory` itself. +Given that this repository already depends on OSx, you may want to reuse the OSx path provided by `protocol-factory` itself in `remappings.txt`: ```diff --@aragon/osx/=lib/osx/packages/contracts/src/ +-@aragon/osx/=lib/osx/src/ +@aragon/protocol-factory/=lib/protocol-factory/ -+@aragon/osx/=lib/protocol-factory/lib/osx/packages/contracts/src/ ++@aragon/osx/=lib/protocol-factory/lib/osx/src/ ``` Then, use the protocol factory to deploy OSx and use its contracts as you need. @@ -191,13 +223,15 @@ You can even [customize these OSx deployments](https://github.com/aragon/protoco ## Deployment 🚀 -Check the available make targets to simulate and deploy the smart contracts: +Check the available recipes to simulate and deploy the smart contracts: ``` -- make predeploy Simulate a protocol deployment -- make deploy Deploy the protocol and verify the source code +- just predeploy Simulate a deployment (dry-run, no broadcast) +- just deploy Run tests, deploy, verify the source code and write logs to ./logs ``` +`just deploy` runs the script in `DEPLOY_SCRIPT` with `--broadcast --verify` and retries pending transactions automatically (`--retries 10 --delay 10`). + ### Deployment Checklist When running a production deployment ceremony, you can use these steps as a reference: @@ -205,7 +239,8 @@ When running a production deployment ceremony, you can use these steps as a refe - [ ] I have cloned the official repository on my computer and I have checked out the `main` branch - [ ] I am using the latest official docker engine, running a Debian Linux (stable) image - [ ] I have run `docker run --rm -it -v .:/deployment debian:bookworm-slim` - - [ ] I have run `apt update && apt install -y make curl git vim neovim bc jq` + - [ ] I have run `apt update && apt install -y curl git vim neovim bc jq` + - [ ] I have installed `just` (e.g. `curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin`) - On **standard EVM networks**: - [ ] I have run `curl -L https://foundry.paradigm.xyz | bash` - [ ] I have run `source /root/.bashrc` @@ -215,18 +250,16 @@ When running a production deployment ceremony, you can use these steps as a refe - [ ] I have run `source /root/.bashrc` - [ ] I have run `foundryup-zksync` - [ ] I have run `cd /deployment` - - [ ] I have run `cp .env.example .env` - - [ ] I have run `make init` + - [ ] I have run `just init ` - [ ] I am opening an editor on the `/deployment` folder, within the Docker container - [ ] The `.env` file contains the correct parameters for the deployment - - [ ] I have created a new burner wallet with `cast wallet new` and copied the private key to `DEPLOYMENT_PRIVATE_KEY` within `.env` - - [ ] I have set the correct `RPC_URL` for the network - - [ ] I have set the correct `CHAIN_ID` for the network + - [ ] I have created a new burner wallet with `cast wallet new` and copied the private key to `DEPLOYER_KEY` within `.env` + - [ ] I have selected the correct network with `just switch ` (sets `RPC_URL` and `CHAIN_ID`) - [ ] I have set `ETHERSCAN_API_KEY` or `BLOCKSCOUT_HOST_NAME` (when relevant to the target network) - - [ ] (TO DO: Add a step to check your own variables here) - - [ ] I have printed the contents of `.env` to the screen + - [ ] I have set `PLUGIN_REPO_MAINTAINER_ADDRESS` (and any other variable your deployment script requires) + - [ ] I have run `just env` and confirmed the resolved values are correct - [ ] I am the only person of the ceremony that will operate the deployment wallet -- [ ] All the tests run clean (`make test`) +- [ ] All the tests run clean (`just test`) - My computer: - [ ] Is running in a safe location and using a trusted network - [ ] It exposes no services or ports @@ -234,52 +267,48 @@ When running a production deployment ceremony, you can use these steps as a refe - Linux: `netstat -tulpn` - Windows: `netstat -nao -p tcp` - [ ] The wifi or wired network in use does not expose any ports to a WAN -- [ ] I have run `make predeploy` and the simulation completes with no errors +- [ ] I have run `just predeploy` and the simulation completes with no errors - [ ] The deployment wallet has sufficient native token for gas - At least, 15% more than the amount estimated during the simulation -- [ ] `make test` still runs clean +- [ ] `just test` still runs clean - [ ] I have run `git status` and it reports no local changes - [ ] The current local git branch (`main`) corresponds to its counterpart on `origin` - [ ] I confirm that the rest of members of the ceremony pulled the last git commit on `main` and reported the same commit hash as my output for `git log -n 1` -- [ ] I have initiated the production deployment with `make deploy` +- [ ] I have initiated the production deployment with `just deploy` ### Post deployment checklist - [ ] The deployment process completed with no errors - [ ] The factory contract was deployed by the deployment address - [ ] All the project's smart contracts are correctly verified on the reference block explorer of the target network. -- [ ] The output of the latest `logs/deployment--.log` file corresponds to the console output -- [ ] A file called `artifacts/deployment--.json` has been created, and the addresses match those logged to the screen +- [ ] The output of the latest `logs/