DAO Scripts Guide
Complete reference for interacting with your Aragon DAO and managing CAP token governance.
Overview
This guide covers all DAO-related scripts for the Cyberia (CAP) token project. These scripts use Aragon OSx contracts directly (no deprecated SDK) for maximum reliability and transparency.
Prerequisites
Before using DAO scripts, ensure you have:
- Created Aragon DAO via https://app.aragon.org
- Installed Token Voting Plugin with CAP token
- Environment Variables configured in
.env:CAP_TOKEN_ADDRESS=0xA6B680A88c16056de7194CF775D04A45D0692C11 ARAGON_DAO_ADDRESS=0x... # From Aragon UI CAP_GOVERNANCE_PLUGIN_ADDRESS=0x... # From Aragon UI → Settings → Plugins
Script Organization
scripts/dao/
├── transfer-governance.ts # Transfer token control to DAO
├── delegate-tokens.ts # Activate voting power
└── osx/
└── get-dao-info.ts # Query DAO configuration
Note: Proposal creation, voting, and execution are done via the Aragon App UI at https://app.aragon.org for the best user experience and reliability.
Setup Scripts
1. Transfer Governance
Purpose: Transfer CAP token control from deployer to Aragon DAO
Command:
What it does:
- Transfers ownership of CAP token to DAO address
- Makes all admin functions require DAO proposals
- IRREVERSIBLE - Cannot undo without DAO vote
After transfer, the DAO controls:
- Tax rate changes (with 24h timelock)
- Pool management (add/remove AMM pairs)
- Fee recipient updates
- Token upgrades (UUPS)
- Minting new tokens (with 7d timelock)
Example output:
✅ Governance successfully transferred to DAO!
📍 Governance Address: 0x9Ccc4Bc3A159F2f812B3790EcaabDa3051C70Ae0
🔗 View DAO: https://app.aragon.org/#/daos/sepolia/0x9Ccc4Bc3A159F2f812B3790EcaabDa3051C70Ae0
Requirements:
- Must be current governance address (deployer initially)
- DAO must exist and be valid
- Sepolia ETH for gas
2. Delegate Tokens
Purpose: Activate your voting power for DAO participation
Command:
What it does:
- Delegates your CAP tokens to yourself
- Activates voting power (required for ERC20Votes)
- Enables you to vote on proposals
- Enables you to create proposals (if you have ≥10,000 CAP)
Why is this needed?
ERC20Votes tokens (like CAP) require explicit delegation to activate voting power. Until you delegate, your token balance doesn't grant voting rights.
Example output:
✅ Your voting power is now active!
📊 Your Voting Stats:
Balance: 1000000 CAP
Voting Power: 1000000 votes
Min to Create Proposal: 10,000 CAP
✅ You have enough power to create proposals!
Requirements:
- Must hold CAP tokens
- Sepolia ETH for gas
- Only need to do this once (unless you transfer all tokens)
Query Scripts
3. Get DAO Info
Purpose: Query DAO configuration and current status
Command:
What it shows:
- CAP Token Info: Name, symbol, supply, governance, taxes
- DAO Info: Address, URI, governance transfer status
- Plugin Info: Voting settings, proposal count, thresholds
- Your Stats: Balance, voting power, delegation status
Example output:
═══════════════════════════════════════════════════════════════
CAP TOKEN INFO
═══════════════════════════════════════════════════════════════
📊 Token Details:
Name: Cyberia
Symbol: CAP
Total Supply: 1000000 CAP
Governance: 0x9Ccc4Bc3A159F2f812B3790EcaabDa3051C70Ae0
💰 Tax Configuration:
Transfer Tax: 1 %
Sell Tax: 1 %
Buy Tax: 0 %
Fee Recipient: 0x37Bb361F12D10F31a963033e1D0B3bb3026D6654
🗳️ Your Voting Power:
Balance: 1000000 CAP
Voting Power: 1000000 votes
Delegated to: 0xYourAddress
Delegated to self: ✅ YES
═══════════════════════════════════════════════════════════════
DAO INFO
═══════════════════════════════════════════════════════════════
🏛️ DAO Details:
Address: 0x9Ccc4Bc3A159F2f812B3790EcaabDa3051C70Ae0
Governance transferred: ✅ YES
═══════════════════════════════════════════════════════════════
TOKEN VOTING PLUGIN INFO
═══════════════════════════════════════════════════════════════
⚙️ Plugin Settings:
Voting Token: 0xA6B680A88c16056de7194CF775D04A45D0692C11
Token Match: ✅ YES
Min Proposer Power: 10000 CAP
Support Threshold: 50 %
Min Participation: 15 %
Min Duration: 86400 seconds ( 24 hours)
Total Proposals: 0
📊 Voting Power Stats:
Total Voting Power: 1000000 votes
Your Voting Power: 1000000 votes
Your Share: 0.1000 %
✅ Can Create Proposals: YES
Requirements:
- Environment variables set
- No gas required (read-only)
Managing Proposals via Aragon UI
All proposal operations (create, vote, execute) should be done through the Aragon App UI for the best experience.
Creating Proposals
- Visit https://app.aragon.org
- Navigate to your DAO
- Click "New Proposal"
- Select action type:
- Add Pool: Use "Contract Interaction" → CAP token →
addPool(address) - Change Taxes: Use "Contract Interaction" → CAP token →
proposeTaxChange(uint256,uint256,uint256) - Update Fee Recipient: Use "Contract Interaction" → CAP token →
setFeeRecipient(address) - Mint Tokens: Use "Contract Interaction" → CAP token →
proposeMint(address,uint256)
- Add Pool: Use "Contract Interaction" → CAP token →
- Fill in parameters
- Add title and description
- Click "Publish"
- Vote automatically recorded (if you have voting power)
Important Security Constraints:
When creating proposals, be aware of these safeguards:
- Minting: Limited to 10M tokens per 30-day rolling period (prevents flash minting attacks). Total supply capped at 42M.
- Fee Recipient: Cannot be set to the CAP token contract address itself (prevents accidental token locking).
- Taxes: Individual tax rates capped at 5% (500 bp), sum of all taxes at 10% (1000 bp).
- Timelock: Tax changes require 24-hour delay before execution; minting requires 7-day delay.
Voting on Proposals
- Visit https://app.aragon.org
- Navigate to your DAO → Proposals
- Click on the proposal
- Review details and actions
- Click "Vote" (Yes/No/Abstain)
- Confirm transaction
Executing Proposals
- After voting period ends and thresholds met
- Visit the proposal page
- Click "Execute"
- Confirm transaction
- Actions are applied to CAP token
Archived: Script-Based Proposal Management
The following sections describe script-based proposal management which has been deprecated in favor of the Aragon UI.
Click to view archived script documentation
4. Create Proposal (DEPRECATED - Use Aragon UI)
Purpose: Create a new DAO proposal to execute token admin functions
Command:
What it does:
- Creates a proposal with encoded action(s)
- Automatically votes YES (if you created it)
- Attempts early execution if thresholds met
- Returns proposal ID and link to Aragon UI
Example proposal: Add test AMM pool
The script includes an example that proposes adding a pool address:
const testPoolAddress = "0x2222222222222222222222222222222222222222";
const addPoolCalldata = capToken.interface.encodeFunctionData("addPool", [testPoolAddress]);
Example output:
✅ Proposal created!
🆔 Proposal ID: 0
🔗 View Proposal:
https://app.aragon.org/dao/ethereum-sepolia/0x9Ccc4Bc3A159F2f812B3790EcaabDa3051C70Ae0/proposals/0
🔍 Can Execute: NO ⏳
⏳ Proposal needs to meet execution criteria:
- Voting period must end
- Minimum participation threshold
- Support threshold (>50%)
💡 To execute later, run:
PROPOSAL_ID=0 npm run dao:execute
Requirements:
- Must have ≥10,000 CAP voting power (min proposer power)
- Must have delegated tokens to self
- Sepolia ETH for gas
Customizing proposals:
To create different proposals, modify the actions array in the script:
// Example: Change tax rates
const proposeTaxCalldata = capToken.interface.encodeFunctionData("proposeTaxChange", [
150, // 1.5% transfer tax
150, // 1.5% sell tax
50, // 0.5% buy tax
]);
const actions = [
{
to: capTokenAddress,
value: 0,
data: proposeTaxCalldata,
},
];
Available actions:
addPool(address)- Add AMM poolremovePool(address)- Remove AMM poolproposeTaxChange(uint256,uint256,uint256)- Propose tax changesetFeeRecipient(address)- Update fee recipientproposeMint(address,uint256)- Propose minting tokensupgradeToAndCall(address,bytes)- Upgrade token implementation
5. Vote on Proposal
Purpose: Vote YES, NO, or ABSTAIN on an active proposal
Command:
PROPOSAL_ID=0 VOTE=yes
Vote options:
yes- Vote in favorno- Vote againstabstain- Neutral vote (counts for participation)
What it does:
- Checks if you can vote (have voting power, haven't voted yet)
- Submits your vote on-chain
- Attempts early execution if thresholds met
- Shows updated vote tally
Example output:
🗳️ Voting "YES" on proposal...
✅ Vote submitted!
📊 Updated Proposal Tally:
Yes: 1000000 CAP
No: 0 CAP
Abstain: 0 CAP
Executed: NO ⏳
⏳ Proposal not yet executable. Requirements:
Support Threshold: >50%
Min Participation: >15%
Min Duration: 86400 seconds
🔗 View Proposal:
https://app.aragon.org/dao/ethereum-sepolia/0x9Ccc4Bc3A159F2f812B3790EcaabDa3051C70Ae0/proposals/0
Requirements:
- Must have voting power at proposal creation time
- Must not have already voted
- Voting period must be active
- Sepolia ETH for gas
Why can't I vote?
- You didn't have voting power when proposal was created
- You already voted on this proposal
- Voting period has ended
- Proposal has been executed
6. Execute Proposal
Purpose: Execute a proposal that has passed voting requirements
Command:
PROPOSAL_ID=0
What it does:
- Checks if proposal can be executed
- Executes all proposal actions on-chain
- Actions are applied to the CAP token contract
Execution requirements:
- Voting period ended (min duration passed)
- Support threshold met (>50% YES votes)
- Min participation met (>15% of voting power participated)
- Not already executed
Example output:
⚡ Executing proposal...
✅ Proposal executed!
🔗 View Transaction:
https://sepolia.etherscan.io/tx/0x...
╔════════════════════════════════════════════════════════════╗
║ 🎉 PROPOSAL EXECUTED! ║
╚════════════════════════════════════════════════════════════╝
✅ The proposal actions have been applied to the CAP token!
💡 Verify the changes:
- If it was a pool addition, check isPool()
- If it was a tax change, check the new tax rates
- If it was a fee recipient change, check feeRecipient()
Requirements:
- Proposal must have passed
- Voting period must have ended
- Sepolia ETH for gas
- Anyone can execute (not just proposer/voters)
Cannot execute yet?
If you get "NO ❌", the script shows why:
⚠️ Proposal cannot be executed yet. Possible reasons:
- Voting period has not ended
- Not enough support (needs >50%)
- Minimum participation not met (needs >15%)
- Already executed
Complete Governance Workflow
Example: Change Tax Rates
Step 1: Create Proposal (modify script to propose tax change)
# Edit scripts/dao/osx/create-proposal.ts with tax change action
# Output: Proposal ID: 0
Step 2: Vote on Proposal
PROPOSAL_ID=0 VOTE=yes
Step 3: Wait for Voting Period
# Min duration: 24 hours (86400 seconds)
# Check status: npm run dao:info
Step 4: Execute Proposal
PROPOSAL_ID=0
# Tax change is now pending (24h timelock)
Step 5: Apply Tax Change (after 24h)
# Create another proposal to call applyTaxChange()
# Or call directly if you're the governance address
Example: Add AMM Pool
Step 1: Create Proposal
# Script includes pool addition example by default
# Output: Proposal ID: 1
Step 2: Vote
PROPOSAL_ID=1 VOTE=yes
Step 3: Wait & Execute
# Wait 24h, then execute
PROPOSAL_ID=1
# Pool is now added immediately
Example: Update Fee Recipient (Set Safe Treasury)
Step 1: Create Proposal (modify script)
const setFeeRecipientCalldata = capToken.interface.encodeFunctionData("setFeeRecipient", ["0xYourSafeAddress"]);
Step 2-4: Vote, wait, execute (same as above)
Environment Variables
Required in .env:
# Network RPC
SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY
# Deployer/signer private key
PRIVATE_KEY=0x...
# CAP Token (from deployment)
CAP_TOKEN_ADDRESS=0xA6B680A88c16056de7194CF775D04A45D0692C11
# Aragon DAO (from app.aragon.org)
ARAGON_DAO_ADDRESS=0x9Ccc4Bc3A159F2f812B3790EcaabDa3051C70Ae0
# Token Voting Plugin (from Aragon UI → Settings → Plugins)
CAP_GOVERNANCE_PLUGIN_ADDRESS=0xf1a054C12659D65892a2b0c4c5136A93b8a5F115
Finding plugin address:
- Go to https://app.aragon.org
- Open your DAO
- Navigate to: Settings → Plugins
- Find Token Voting plugin
- Copy the contract address
Script Technical Details
Direct Contract Calls (No SDK)
All scripts use direct ethers.js contract calls to Aragon OSx contracts:
// TokenVoting plugin ABI
const tokenVotingABI = [
"function createProposal(...) external returns (uint256)",
"function vote(uint256 _proposalId, uint8 _voteOption, bool _tryEarlyExecution) external",
"function execute(uint256 _proposalId) external",
// ... other functions
];
const tokenVoting = new ethers.Contract(pluginAddress, tokenVotingABI, signer);
Benefits:
- No deprecated SDK dependencies
- Full transparency (see exact contract calls)
- More reliable and maintainable
- Works with any Aragon OSx DAO
Vote Options
Vote options are encoded as numbers:
1= Abstain2= Yes3= No
Scripts accept human-readable input (yes, no, abstain) and convert to numbers.
Early Execution
Scripts pass tryEarlyExecution: true to voting functions. If a proposal meets thresholds before the voting period ends, it will execute immediately.
Early execution criteria:
- Support threshold met (>50%)
- Minimum participation met (>15%)
- Impossible to change outcome even with remaining votes
Troubleshooting
"Insufficient voting power"
Cause: You don't have ≥10,000 CAP to create proposals
Solution:
- Acquire more CAP tokens
- Or reduce
minProposerVotingPowervia DAO proposal (requires existing proposal)
"You haven't delegated your tokens"
Cause: Voting power not activated
Solution:
"You cannot vote on this proposal"
Causes:
- Already voted → Check Aragon UI
- No voting power at creation → Delegate tokens before next proposal
- Voting period ended → Proposal can be executed if passed
- Already executed → Check Aragon UI
"Proposal cannot be executed yet"
Causes:
- Voting period not ended → Wait 24 hours
- Not enough YES votes → Need >50% support
- Not enough participation → Need >15% of voting power
- Already executed → Check Aragon UI
"NOT_GOVERNANCE" error
Cause: Trying to call admin function directly (not via DAO)
Solution: All admin functions require DAO proposals after governance transfer
Plugin address not found
Solution:
- Open Aragon UI: https://app.aragon.org
- Navigate to your DAO
- Settings → Plugins
- Copy Token Voting plugin address
- Add to
.envasCAP_GOVERNANCE_PLUGIN_ADDRESS
Aragon UI vs Scripts
When to use Aragon UI (https://app.aragon.org):
- View all proposals and their status
- Browse voting history
- Check DAO configuration
- Visual proposal creation (easier for non-technical users)
- Monitor vote tallies in real-time
When to use scripts:
- Automated workflows (CI/CD)
- Programmatic proposal creation
- Batch operations
- Integration with other tools
- Technical control and transparency
Best practice: Use both! Create proposals via scripts, monitor via UI.
Security Best Practices
Before transferring governance:
- ✅ Test DAO creation on Sepolia first
- ✅ Verify token voting plugin is correctly configured
- ✅ Delegate tokens to yourself
- ✅ Create test proposal and execute it successfully
- ✅ Ensure backup plan (emergency multisig?)
After transferring governance:
- ✅ Test proposal creation immediately
- ✅ Document all admin functions requiring DAO votes
- ✅ Set up monitoring for proposals
- ✅ Educate token holders about voting
- ✅ Consider Gnosis Safe with Zodiac for treasury
Proposal creation:
- ✅ Test actions on Sepolia first
- ✅ Document proposal intent clearly (use IPFS metadata)
- ✅ Double-check addresses and parameters
- ✅ Consider timelocks (taxes: 24h, minting: 7d)
- ✅ Announce proposals to community
Advanced Usage (For Script Development)
Multiple Actions in One Proposal
const actions = [
{
to: capTokenAddress,
value: 0,
data: capToken.interface.encodeFunctionData("addPool", [pool1]),
},
{
to: capTokenAddress,
value: 0,
data: capToken.interface.encodeFunctionData("addPool", [pool2]),
},
{
to: capTokenAddress,
value: 0,
data: capToken.interface.encodeFunctionData("proposeTaxChange", [100, 100, 0]),
},
];
All actions execute atomically if proposal passes.
IPFS Metadata
For rich proposal descriptions:
// Upload description to IPFS, get CID
const ipfsCID = "QmXyz...";
const metadata = ethers.toUtf8Bytes(`ipfs://${ipfsCID}`);
Metadata format (JSON on IPFS):
Querying Past Proposals
const proposalCount = await tokenVoting.proposalCount();
console.log("Total proposals:", proposalCount);
for (let i = 0; i < proposalCount; i++) {
const proposal = await tokenVoting.getProposal(i);
console.log(`Proposal ${i}:`, proposal);
}
Summary: NPM Commands
| Command | Purpose | Requirements |
|---|---|---|
npm run dao:transfer-governance |
Transfer token to DAO | Deployer key, gas |
npm run dao:delegate |
Activate voting power | CAP tokens, gas |
npm run dao:info |
Query DAO status | None (read-only) |
Proposal Management: Use Aragon UI at https://app.aragon.org for creating, voting on, and executing proposals.
Additional Resources
- Aragon OSx Docs: https://devs.aragon.org/
- Aragon App: https://app.aragon.org
- CAP Token Contract: https://sepolia.etherscan.io/address/0xA6B680A88c16056de7194CF775D04A45D0692C11
- Token Voting Plugin Docs: https://devs.aragon.org/docs/osx/how-to-guides/plugin-development/token-voting-plugin
- Zodiac Safe Setup: See docs/zodiac-roles-config.json
Questions or issues? Open an issue at https://github.com/cyberia-to/cyberia-token/issues