DAO governance
Propose, vote, and execute protocol changes through the Uruk DAO and its multi-sig.
DAO governance
The Uruk DAO (dao-governance contract) controls every protocol parameter: market deployment, pool creation, collateral whitelists, partner registration, oracle and KYC providers, and contract upgrades.
Who can govern
- Governance runs through a multi-sig wallet (wallet id
0, created at deploy). - Only signers of that wallet may propose and vote. Governance is deliberately KYC-free. Membership is the access control.
- One signer = one vote. Passing threshold = the wallet's multi-sig threshold.
- Voting period is 48h; execution has an additional 24h timelock (
execute_after = end_time + 24h).
Check membership with is_governance_signer(addr). The webapp uses it to gate the Vote / Propose UI.
Lifecycle
propose(proposer, title, description, call_data) → proposal id
vote(voter, proposal_id, support) → one vote per signer
finalise(proposal_id) → status Passed once yes ≥ threshold
execute(executor, proposal_id) → runs call_data after timelock
cancel(proposer, proposal_id) → proposer only, while Activeget_proposal_count()returns the next proposal id. Call it beforepropose().execute()routescall_datato cross-contract calls (see actions below).has_voted(id, voter)andget_proposal(id)back the dashboard.
Privileged actions need multi-sig
A bitmask decides which action types also require on-chain multi-sig approval even after the vote passes: signer management, oracle providers, KYC verifiers, deploy/activate assets, and contract upgrades.
propose_and_queue_multisig(...) → (proposal_id, multisig_tx_id)
approve_multisig_tx(signer, tx_id, approve)
execute_multisig_tx(executor, tx_id) → runs the queued call_dataUseful views: get_pending_multisig_txs(wallet_id), get_multisig_tx_approvals(tx_id), get_multisig_tx_summary(tx_id), get_signers(wallet_id).
Proposal actions
call_data is packed as [action_type: u32 LE][payload…]. Action types:
| Action | What it does |
|---|---|
deploy_asset (0) | Register a synthetic market + whitelist its collateral in one execution |
deactivate (1) | Deactivate a partner on PartnerRegistry |
adjust_earnings (3) | Change a partner's revenue share |
adjust_ratio (4) | Update global min collateral ratio / liquidation penalty |
create_pool (5) | Create a liquidity pool (pool_id, token_a, token_b, fee_tier) |
add_signer (6) / remove_signer (7) | Multi-sig signer management |
oracle_add_provider (8) / oracle_remove_provider (9) / oracle_set_min_providers (10) | Oracle-twap provider + quorum management |
kyc_add_verifier (11) / kyc_remove_verifier (12) | Compliance-registry verifier management |
set_collateral_allowed (13) | Whitelist / de-whitelist a collateral token |
register_partner (14) | Approve a partner join application |
activate_partner_asset (15) | Make a partner-submitted synth live |
upgrade_contract (16) | Replace a protocol contract's Wasm (storage preserved) |
generic (99) | Legacy param update (ParamCR / ParamBorrowFee / ParamLiqPenalty) |
REST API
Governance state is indexed and mirrored by the backend:
| Method | Path | Description |
|---|---|---|
| GET | /api/proposals | List proposals (?status=&type=) |
| GET | /api/proposals/:id | Single proposal (db uuid or on-chain id) |
| POST | /api/proposals | Record a proposal created on-chain |
| PATCH | /api/proposals/:id | Sync status/votes after vote() / execute() |
| GET | /api/proposals/:id/votes | Per-voter audit trail |
| POST | /api/proposals/:id/votes | Record an on-chain vote |
| GET | /api/multisig/config | Multi-sig wallets config |
| GET | /api/multisig/wallets / /wallets/:id | Wallet list + detail |
| POST | /api/multisig/wallets | Create a wallet (DAO only) |
| GET | /api/multisig/transactions/pending | Txs awaiting signer approval |
| GET | /api/multisig/transactions/ready | Txs that reached threshold |
| POST | /api/multisig/transactions | Queue a tx for approval |
Keep state alive
Soroban state expires unless bumped. Keepers (or anyone) may call the permissionless entrypoint to extend TTLs. No auth, no state change, only ledger lifetimes:
- DAO:
extend_ttl(proposal_id, threshold, extend_to)extends the instance plus one proposal's entries - Liquidity pool:
extend_ttl(pool_id, provider?, threshold, extend_to) - Synthetic engine:
extend_ttl(owner, synth, threshold, extend_to)