# Governance
JuiceSwap uses the same veto-based governance system as JuiceDollar, powered by JUICE token voting.
# Governance Philosophy
JuiceSwap's governance embodies the cypherpunk principle of "code as law":
- No admin keys - No privileged accounts can change protocol parameters
- Veto-based - Proposals pass by default unless actively blocked
- Minority protection - Only 2% voting power needed to veto
- Time-weighted voting - Long-term holders have more influence
This design maximizes permissionlessness while still allowing the community to protect against malicious proposals.
# How Governance Works
# The JuiceSwapGovernor
The JuiceSwapGovernor contract manages all governance actions for JuiceSwap:
- Anyone can propose by paying 1,000 JUSD
- 14-day minimum waiting period for community review
- JUICE holders can veto with 2% voting power
- If no veto, anyone can execute the proposal
Propose → Wait 14 days → Execute (if no veto)
↑ ↓
└─── Veto (2% votes) ─────┘
# Creating Proposals
# Proposal Types
JuiceSwapGovernor can execute calls on any contract, enabling:
| Target | Example Actions |
|---|---|
| Factory | Enable new fee tiers |
| FeeCollector | Update TWAP parameters, change collector |
| Pools | Set protocol fee |
| Any contract | Custom governance actions |
# Making a Proposal
function propose(
address target, // Contract to call
bytes calldata data, // Encoded function call
uint256 applicationPeriod, // Veto period (≥14 days)
string calldata description // Human-readable description
) external returns (uint256 proposalId)
# Example: Enable New Fee Tier
const governor = new ethers.Contract(GOVERNOR_ADDRESS, governorAbi, signer);
// Approve 1000 JUSD fee
await jusd.approve(GOVERNOR_ADDRESS, ethers.parseEther("1000"));
// Encode the function call
const feeCollector = new ethers.Interface(feeCollectorAbi);
const callData = feeCollector.encodeFunctionData("enableFeeAmount", [
100, // 0.01% fee
1 // tick spacing
]);
// Create proposal
const proposalId = await governor.propose(
FEE_COLLECTOR_ADDRESS,
callData,
14 * 24 * 60 * 60, // 14 days
"Enable 0.01% fee tier for stable pairs"
);
# Proposal Fee
The 1,000 JUSD fee is transferred directly to the JUICE Equity contract, increasing JUICE token value. This:
- Prevents spam proposals
- Ensures proposers have skin in the game
- Benefits all JUICE holders
# Voting Power
# How Votes Are Calculated
JuiceSwap uses the same voting mechanism as JuiceDollar:
votes = JUICE balance × holding duration
| Factor | Effect |
|---|---|
| More JUICE | More votes |
| Longer holding | More votes |
| Recently received | Zero votes initially |
# Checking Voting Power
const governor = new ethers.Contract(GOVERNOR_ADDRESS, governorAbi, provider);
// Get your voting power (with delegates)
const votingPower = await governor.getVotingPower(myAddress, helpers);
// Get as percentage (basis points)
const percentage = await governor.getVotingPowerPercentage(myAddress, helpers);
// 200 = 2%, 1000 = 10%
# Vote Delegation
Small holders can combine voting power through delegation:
// On the JUICE (Equity) contract
await juice.delegateVoteTo(delegateAddress);
When vetoing, include all addresses that delegated to you in the helpers array.
# Vetoing Proposals
# Requirements
To veto a proposal, you need:
- 2% of total voting power (your votes + delegated votes)
- Veto before the application period ends
# Executing a Veto
function veto(
uint256 proposalId,
address[] calldata helpers // Addresses that delegated to you
) external
// Helpers must be sorted ascending, no duplicates
const helpers = [
"0x1111...", // Alice delegated to me
"0x2222...", // Bob delegated to me
].sort();
await governor.veto(proposalId, helpers);
# Flash Loan Protection
The voting system is immune to flash loan attacks:
- Votes = balance × holding duration
- Flash-loaned tokens have 0 seconds holding duration
- Therefore flash loans provide 0 votes
# Executing Proposals
After the application period ends without a veto:
// Anyone can execute
await governor.execute(proposalId);
The encoded function call is executed on the target contract.
# Proposal States
enum ProposalState {
NotFound, // Proposal doesn't exist
Pending, // Still in application period
Ready, // Can be executed
Vetoed, // Was vetoed
Executed // Already executed
}
const state = await governor.state(proposalId);
# Fee Collector Governance
The JuiceSwapFeeCollector has several governable parameters:
# Protection Parameters
function setProtectionParams(
uint32 _twapPeriod, // TWAP period (min 5 minutes)
uint256 _maxSlippageBps // Max slippage (max 10%)
) external onlyOwner
| Parameter | Default | Range |
|---|---|---|
| TWAP Period | 30 minutes | 5 min - unlimited |
| Max Slippage | 2% (200 bps) | 0 - 10% |
# Authorized Collector
function setCollector(address collector) external onlyOwner
Only the authorized collector can call collectAndReinvestFees().
# Factory Control
// Enable new fee tier
function enableFeeAmount(uint24 fee, int24 tickSpacing) external onlyOwner
// Transfer factory ownership (emergency)
function setFactoryOwner(address _owner) external onlyOwner
# Governance Events
// Proposal lifecycle
event ProposalCreated(
uint256 indexed proposalId,
address indexed proposer,
address indexed target,
bytes data,
uint256 executeAfter,
string description
);
event ProposalExecuted(uint256 indexed proposalId, address indexed executor);
event ProposalVetoed(uint256 indexed proposalId, address indexed vetoer);
event ProposalFeeCollected(uint256 indexed proposalId, uint256 amount);
# Governance Constants
| Constant | Value | Description |
|---|---|---|
PROPOSAL_FEE | 1,000 JUSD | Cost to create proposal |
MIN_APPLICATION_PERIOD | 14 days | Minimum veto period |
QUORUM | 2% | Voting power needed for veto |
# Best Practices
# For Proposers
- Discuss first - Share your proposal in community forums
- Use longer periods - Give time for review (21+ days recommended)
- Document clearly - Explain what the proposal does and why
- Test thoroughly - Verify the encoded call data
# For JUICE Holders
- Hold long-term - Voting power increases over time
- Monitor proposals - Watch for new governance activity
- Delegate wisely - Choose delegates who share your values
- Veto responsibly - Only block genuinely harmful proposals
# Integration with JuiceDollar
JuiceSwap governance uses the same JUICE token as JuiceDollar:
| Aspect | Shared |
|---|---|
| Token | JUICE (Equity) |
| Voting mechanism | Time-weighted |
| Veto threshold | 2% |
| Delegation | Same system |
This means:
- JUICE holders govern both JuiceDollar and JuiceSwap
- Voting power applies to both protocols
- A single delegate can veto proposals in either system
# Contract Addresses
# Mainnet (Chain ID: 4114)
| Contract | Address |
|---|---|
| JuiceSwapGovernor | 0x51f3D5905C768CCA2D4904Ca7877614CeaD607ae (opens new window) |
| JuiceSwapFeeCollector | 0xD2D68A452A6f5d9090153f52E64f23cc7fF8A97b (opens new window) |
| JUICE (Equity) | 0x2A36f2b204B46Fd82653cd06d00c7fF757C99ae4 (opens new window) |
| UniswapV3Factory | 0xd809b1285aDd8eeaF1B1566Bf31B2B4C4Bba8e82 (opens new window) |
# Testnet (Chain ID: 5115)
| Contract | Address |
|---|---|
| JuiceSwapGovernor | 0x8AFD7CB73Ce85b44996B86ec604c125af244A2B8 (opens new window) |
| JuiceSwapFeeCollector | 0xfac6303F78A2b316a20eD927Ba0f7a7d07AaC47E (opens new window) |
| JUICE (Equity) | 0x7fa131991c8A7d8C21b11391C977Fc7c4c8e0D5E (opens new window) |
| UniswapV3Factory | 0xdd6Db52dB41CE2C03002bB1adFdCC8E91C594238 (opens new window) |