This reposity contains a library of OSx conditions, meant to be used by any DAO wishing to guard contract functions by using common permission patterns.
Halborn: Safe owner condition
- Commit ID: 12bfb3b3
Halborn: audit report
- Commit ID: df9320ab
- Execute Selector Condition: only allows a predefined set of function selectors to be invoked via
execute() - Selector Condition: only allows a predefined set of function selectors to be invoked directly
- Safe Owner condition: restricts the permission to only be available to the owners of a given Safe
See the ConditionFactory address on each supported network in npm-artifacts/src/addresses.json, or install @aragon/condition-library-artifacts.
The artifacts package is released by merging a PR that bumps npm-artifacts/package.json#version. CI tags and publishes automatically on merge — see npm-artifacts/README.md.
Requirements: Foundry and just.
The project uses just-foundry, a thin task runner that resolves per-network config (RPC, chain ID, verifier, etc.) automatically. Initialize the submodules and pick a network:
git submodule update --init --recursive
just init sepolia
cp .env.example .env # then fill in DEPLOYER_KEY, ETHERSCAN_API_KEY, …Run just (or just help) to list available recipes:
[setup]
init network="mainnet" Initialize for a given network
switch network override="" Select active network (pass "override" to fork the config locally)
setup Install Foundry
[script]
predeploy Simulate a factory deployment
deploy *args Run tests, deploy the factory, verify, log
precreate Simulate Create.s.sol
create *args Run tests, instantiate conditions via Create.s.sol, verify, log
[test]
test *args Run unit tests
test-fork *args Run fork tests (requires RPC_URL)
test-coverage HTML coverage report under ./report
[helpers]
env Show resolved environment + sources
balance Deployer wallet balance
[develop]
clean Clean compiler artifacts and reports
anvil Local fork of the active network
[verification]
verify type="" script="" Verify all contracts from the latest broadcast
Hidden helpers (run directly): gas-price, nonce, clean-nonce <n>, clean-nonces "n1 n2 …", refund. See lib/just-foundry/README.md.
Two options:
- Plain
.envat the repo root (gitignored). Start from.env.example. - Recommended:
vars— an age-encrypted local store that supplies secrets to every project automatically. Install withjust install-vars. The required keys are listed in.vars.yaml.
Network-level config (RPC URL, chain ID, verifier) lives in lib/just-foundry/networks/<network>.env. To customize a network locally without editing the submodule, run just switch <network> override and edit the resulting .env.<network> at the repo root.
just predeploy # simulate
just deploy # run tests, broadcast, verify, write logs/Deploy-<network>-<ts>.log
just precreate # simulate the Create script
just create # run Create.s.sol to instantiate conditions- I have cloned the official repository on my computer and I have checked out the corresponding 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:trixie-slim(Debian 13 or newer) - I have run
apt update && apt install -y curl git just vim neovim bc jq - On standard EVM networks:
- I have run
just setup(installs Foundry)
- I have run
- On ZkSync networks:
- I have run
just setup-zksync
- I have run
- I have run
cd /deployment - I have run
git submodule update --init --recursive - I have run
just init <network>(e.g.just init sepolia) - I have run
cp .env.example .envand filled in the secrets
- I have run
- I am opening an editor on the
/deploymentfolder, within the Docker container - The
.envfile contains the correct parameters for the deployment- I have created a brand new burner wallet with
cast wallet newand copied the private key toDEPLOYER_KEYwithin.env -
just envshows the expected network, verifier, and resolved secrets
- I have created a brand new burner wallet with
- All the tests run clean (
just test) - My deployment wallet is a newly created account, ready for safe production deploys.
- My computer:
- Is running in a safe location and using a trusted network
- It exposes no services or ports
- The wifi or wired network in use does not expose any ports to a WAN
- I have previewed my deploy without any errors
just predeploy
- The deployment wallet has sufficient native token for gas
- At least, 15% more than the estimated simulation
-
just teststill runs clean - I have run
git statusand it reports no local changes - The current local git branch (
main) corresponds to its counterpart onorigin- I confirm that the rest of members of the ceremony pulled the last commit of my branch and reported the same commit hash as my output for
git log -n 1
- I confirm that the rest of members of the ceremony pulled the last commit of my branch and reported the same commit hash as my output for
- I have initiated the production deployment with
just deploy
- The deployment process completed with no errors
- The output of the latest
logs/Deploy-*.logfile corresponds to the console output - I have updated the relevant network entry in
npm-artifacts/src/addresses.jsonwith the new factory address (the raw deployment receipt is atdeployments/Deploy-<network>-<ts>.json) - I have uploaded the log file to a remote place
- 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.
- This also includes contracts that aren't explicitly deployed (deployed on demand)
- I have transferred the remaining funds of the deployment wallet to the address that originally funded it
just refund
OSx DAO's are designed to hold all the assets and rights by themselves. On the other hand, plugins are custom opt-in pieces of logic that can implement any type of governance. They are meant to eventually make the DAO execute a certain set of actions.
The whole ecosystem is governed by the DAO's permission database, which is used to restrict actions to only the role holding the appropriate permission.
An Aragon DAO is a set of permissions that are used to define who can do what, and where.
A permission looks like:
- An address
whoholdsMY_PERMISSION_IDon a target contractwhere
Brand new DAO's are deployed with a ROOT_PERMISSION assigned to its creator, but the DAO will typically deployed by the DAO factory, which will install all the requested plugins and drop the ROOT permission after the set up is done.
Managing permissions is made via two functions that are called on the DAO:
function grant(address _where, address _who, bytes32 _permissionId);
function revoke(address _where, address _who, bytes32 _permissionId);For the cases where an unrestricted permission is not derisable, a Permission Condition can be used.
Conditional permissions look like this:
- An address
whoholdsMY_PERMISSION_IDon a target contractwhere, onlywhenthe condition contract approves it
Conditional permissions are granted like this:
function grantWithCondition(
address _where,
address _who,
bytes32 _permissionId,
IPermissionCondition _condition
);See the condition contract boilerplate. It provides the plumbing to easily restrict what the different multisig plugins can propose on the OptimisticVotingPlugin.
Learn more about OSx permissions
just test # unit tests
just test-fork # fork tests (requires RPC_URL)
just test-coverage # HTML coverage report under ./reportTest files live in ./test. Add new test contracts directly in Solidity.