Integration with Aragon (DAO framework)
Aragon is one of the oldest DAO frameworks (since 2017), having gone through several architectural iterations. The current version — Aragon OSx (Open Source, launched in 2023) — is a complete overhaul: modular plugin architecture instead of monolithic App framework v1. If you're considering Aragon for a new project — you're looking at OSx.
Aragon OSx Architecture
DAO, PermissionManager, Plugin
Three central concepts:
DAO contract — a minimalist core. Stores the treasury, has an execute() method for calling arbitrary actions. By itself, it knows nothing about voting.
PermissionManager — built into the DAO. Manages who (subject) can do what (permission) with whom (target). All access logic goes through permissions, not hardcoded roles.
Plugin — a smart contract with specific functionality (voting, multisig, token management). A plugin is installed in the DAO through PluginSetup + PluginSetupProcessor. Upon installation, the plugin receives necessary permissions through the PermissionManager.
DAO
├── PermissionManager
│ ├── TokenVoting plugin → EXECUTE_PERMISSION on DAO
│ ├── Multisig plugin → EXECUTE_PERMISSION on DAO
│ └── AdminPlugin → ROOT_PERMISSION (for initial setup)
└── execute() → calls target contracts
Key idea: a DAO can have multiple governance mechanisms simultaneously. For example, multisig for quick decisions with small budgets + token voting for major decisions.
Plugin Installation
Installation through PluginSetupProcessor — a special permissioned Aragon contract. The process is two-phase:
-
prepareInstallation()— deploy plugin contract, compute necessary permissions (returnsPreparedSetupData) -
applyInstallation()— apply permissions in the DAO
Why two-phase: permissions are applied only if the DAO itself approved it through a governance proposal. You can't install a plugin in an active DAO without member approval.
// Data for applyInstallation
struct ApplyInstallationParams {
PluginRepo pluginSetupRepo; // plugin repository
IPluginSetup.SetupPayload setupPayload;
PermissionLib.MultiTargetPermission[] permissions; // permissions to apply
bytes32 helpersHash;
}
PluginRepo and versioning
Each plugin has its own PluginRepo — a version registry. This allows updating a plugin through governance without changing the DAO core. Version: [release, build]. Release — breaking changes, build — patches.
Aragon supports ENS names for PluginRepo: token-voting.plugin.dao.eth — the official TokenVoting plugin. Custom plugins are deployed similarly.
Official Aragon Plugins
TokenVoting
The most used plugin. Voting power = ERC20Votes balance at snapshot. Configured on installation:
const tokenVotingSettings = {
votingMode: VotingMode.EarlyExecution, // or Standard, VoteReplacement
supportThreshold: pctToRatio(50), // 50% FOR to pass
minParticipation: pctToRatio(15), // 15% quorum
minDuration: 60 * 60 * 24 * 3, // minimum 3 days
minProposerVotingPower: BigInt("1000000000000000000"), // 1 token
}
VotingMode.EarlyExecution — a proposal can be executed before voting ends, if the result is mathematically predetermined. Useful for urgent changes with clear consensus.
Multisig
N-of-M multisig as a governance plugin. A proposal is created by one member, executed after M signatures. Useful as an emergency override or for operational decisions without waiting for full token voting.
Integration of two plugins: TokenVoting for strategic decisions + Multisig for operational with amount limits.
Admin
A special plugin for the initial phase: one address (founder multisig) has ROOT_PERMISSION. Allows quickly setting up the DAO before transferring control to token holders. Must be uninstalled after transitioning to decentralized governance — leaving Admin plugin active = centralization risk.
Custom Plugin Development
PluginSetup Structure
For a custom plugin you need two contracts: the Plugin itself and its PluginSetup (factory + permissions declaration).
contract CustomVotingPlugin is Plugin {
bytes32 public constant EXECUTE_PROPOSAL_PERMISSION_ID = keccak256("EXECUTE_PROPOSAL_PERMISSION");
constructor(IDAO _dao) Plugin(_dao) {}
function executeProposal(uint256 proposalId) external auth(EXECUTE_PROPOSAL_PERMISSION_ID) {
// execution logic
dao().execute(
bytes32(proposalId),
actions,
allowFailureMap
);
}
}
contract CustomVotingPluginSetup is PluginSetup {
function prepareInstallation(address _dao, bytes calldata _data)
external
returns (address plugin, PreparedSetupData memory preparedSetupData)
{
// Deploy plugin
plugin = address(new CustomVotingPlugin(IDAO(_dao)));
// Declare permissions
PermissionLib.MultiTargetPermission[] memory permissions =
new PermissionLib.MultiTargetPermission[](1);
permissions[0] = PermissionLib.MultiTargetPermission({
operation: PermissionLib.Operation.Grant,
where: _dao,
who: plugin,
condition: PermissionLib.NO_CONDITION,
permissionId: DAO(payable(_dao)).EXECUTE_PERMISSION_ID()
});
preparedSetupData.permissions = permissions;
}
}
Conditional Permissions
PermissionManager supports conditions: permission grants only when an on-chain condition is met. Example: a plugin can call execute() only for transactions under 10 ETH.
contract ValueCondition is IPermissionCondition {
uint256 public maxValue;
function isGranted(address, address, bytes32, bytes calldata _data)
external view returns (bool)
{
(,CallstateLib.Action[] memory actions,) = abi.decode(_data, (bytes32, CallstateLib.Action[], uint256));
for (uint i = 0; i < actions.length; i++) {
if (actions[i].value > maxValue) return false;
}
return true;
}
}
This allows building complex permission logic without modifying core contracts.
SDK Integration
Aragon SDK (TypeScript) significantly simplifies interaction:
import { Client, TokenVotingClient, VotingMode } from "@aragon/sdk-client";
import { context } from "./context"; // Web3Provider + config
const client = new Client(context);
const tokenVotingClient = new TokenVotingClient(context);
// Create a proposal
const proposalParams = {
pluginAddress: TOKEN_VOTING_PLUGIN_ADDRESS,
metadataUri: await client.methods.pinMetadata({
title: "Increase protocol fee",
summary: "I propose raising fees from 0.3% to 0.5%",
description: "Detailed rationale...",
resources: [],
}),
actions: [
client.encoding.updateFeeAction(protocolAddress, 50),
],
executeOnPass: true,
creatorVote: Vote.YES,
};
const tx = await tokenVotingClient.methods.createProposal(proposalParams);
The SDK handles IPFS pinning for metadata (metadata is stored off-chain, only URI on-chain), action encoding, event listening.
When to choose Aragon vs OpenZeppelin Governor
| Criterion | Aragon OSx | OZ Governor |
|---|---|---|
| Plugin ecosystem | Rich, ready plugins | Minimal |
| Customization | High through plugins | High through modules |
| SDK/tooling | Excellent TypeScript SDK | Limited |
| Deployment complexity | Higher | Lower |
| Special handling | PermissionManager — powerful | Simpler, but less flexible |
| Audited baseline | Yes, core contracts | Yes, OZ standards |
Aragon is preferable if: you need multi-plugin governance, plan evolution of mechanisms over time, value an ecosystem of compatible components. OZ Governor is preferable if: you need simple and audited baseline Governor without overhead, your team is already familiar with OZ, no plans for complex plugin architecture.
Developing a DAO on Aragon OSx with custom plugin and SDK integration — 4-8 weeks. Setting up standard plugins (TokenVoting + Multisig) with frontend — 2-3 weeks.







