# Implémentation d'une DAO sur 4NK : Spécification Technique **Version:** 1.0 **Date:** 1 octobre 2025 **Prérequis:** [4NK_IDENTITY_AND_PROCESS_SPEC.md](./4NK_IDENTITY_AND_PROCESS_SPEC.md) --- ## Table des matières 1. [Architecture d'une DAO 4NK](#1-architecture-dune-dao-4nk) 2. [Mécanismes de gouvernance](#2-mécanismes-de-gouvernance) 3. [Système de vote on-chain](#3-système-de-vote-on-chain) 4. [Gestion de trésorerie](#4-gestion-de-trésorerie) 5. [Propositions et exécution](#5-propositions-et-exécution) 6. [Tokenisation et pondération](#6-tokenisation-et-pondération) 7. [Sécurité et attaques](#7-sécurité-et-attaques) 8. [Implémentation de référence](#8-implémentation-de-référence) --- ## 1. Architecture d'une DAO 4NK ### 1.1 Vue d'ensemble Une DAO (Decentralized Autonomous Organization) sur 4NK exploite les primitives existantes pour créer une organisation autonome avec: - **Gouvernance on-chain** via ProcessState - **Identité cryptographique** via Silent Payments - **Consensus distribué** via ValidationRules - **Trésorerie Bitcoin** via UTXO management - **Auditabilité complète** via blockchain commitments ``` ┌────────────────────────────────────────────────────────────┐ │ DAO 4NK │ ├────────────────────────────────────────────────────────────┤ │ │ │ GOUVERNANCE TRÉSORERIE │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ Processus │ │ Multisig │ │ │ │ de vote │ │ UTXO Pool │ │ │ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ │ ┌──────────────┐ │ │ │ └─►│ Proposition │◄───────┘ │ │ │ Executable │ │ │ └──────┬───────┘ │ │ │ │ │ ▼ │ │ ┌────────────────────┐ │ │ │ Exécution on-chain│ │ │ │ (Bitcoin Tx) │ │ │ └────────────────────┘ │ │ │ │ MEMBRES │ │ ┌──────────┬──────────┬──────────┐ │ │ │ Founder │ Member │ Delegate │ │ │ │ (100%) │ (1 vote) │ (N votes)│ │ │ └──────────┴──────────┴──────────┘ │ └────────────────────────────────────────────────────────────┘ ``` ### 1.2 Composants techniques #### A. Processus DAO principal ```rust pub struct DaoProcess { // Processus 4NK contenant la gouvernance process: Process, // Configuration de la DAO config: DaoConfig, // État actuel current_state: DaoState, } pub struct DaoConfig { // Nom de la DAO name: String, // Type de vote voting_system: VotingSystem, // Quorum requis (0.0 à 1.0) quorum: f32, // Durée de vote (en blocs Bitcoin) voting_period_blocks: u32, // Délai d'exécution (timelock) execution_delay_blocks: u32, // Trésorerie treasury_address: SilentPaymentAddress, } pub struct DaoState { // Membres de la DAO members: HashMap, // Propositions actives active_proposals: Vec, // Propositions exécutées executed_proposals: Vec, // Balance de trésorerie treasury_balance: Amount, } ``` #### B. Structure de membre DAO ```rust pub struct MemberInfo { // Pairing process ID du membre member_id: OutPoint, // Adresses Silent Payment sp_addresses: Vec, // Poids de vote (tokens) voting_power: u64, // Délégation (optionnel) delegated_to: Option, // Date d'adhésion (hauteur de bloc) joined_at: u32, // Récompenses accumulées rewards: Amount, } impl MemberInfo { pub fn effective_voting_power(&self, state: &DaoState) -> u64 { if let Some(delegate) = self.delegated_to { 0 // Votes délégués } else { // Inclure les votes délégués à ce membre let delegated_votes: u64 = state.members.values() .filter(|m| m.delegated_to == Some(self.member_id)) .map(|m| m.voting_power) .sum(); self.voting_power + delegated_votes } } } ``` ### 1.3 Processus fondamentaux Une DAO 4NK repose sur **trois processus distincts** : ``` ┌─────────────────────────────────────────────────────┐ │ Processus 1: GOUVERNANCE │ │ ├─ États: Propositions, Votes, Paramètres │ │ ├─ Rôles: Founders, Members, Delegates │ │ └─ Validations: Quorum-based │ └─────────────────────────────────────────────────────┘ │ ▼ Référence via process_id ┌─────────────────────────────────────────────────────┐ │ Processus 2: TRÉSORERIE (Multisig) │ │ ├─ États: UTXO pool, Dépenses │ │ ├─ Rôles: Signataires (M-of-N) │ │ └─ Validations: Signatures cryptographiques │ └─────────────────────────────────────────────────────┘ │ ▼ Référence via execution_id ┌─────────────────────────────────────────────────────┐ │ Processus 3: ADHÉSIONS (Pairing collectif) │ │ ├─ États: Liste des membres │ │ ├─ Rôles: Admission committee │ │ └─ Validations: Vote d'admission │ └─────────────────────────────────────────────────────┘ ``` **Avantages de cette architecture:** - **Séparation des responsabilités** : Gouvernance ≠ Trésorerie - **Évolutivité** : Chaque processus peut évoluer indépendamment - **Sécurité** : Compromission d'un processus n'affecte pas les autres - **Auditabilité** : Traçabilité complète de chaque aspect --- ## 2. Mécanismes de gouvernance ### 2.1 Types de vote #### A. Vote simple (1 membre = 1 vote) ```rust pub enum VotingSystem { Simple, // 1 membre = 1 vote Weighted, // Vote pondéré par tokens Quadratic, // Vote quadratique (√tokens) Delegated, // Délégation de votes Reputation, // Basé sur la réputation } impl VotingSystem { pub fn calculate_vote_power(&self, member: &MemberInfo, state: &DaoState) -> u64 { match self { VotingSystem::Simple => 1, VotingSystem::Weighted => member.effective_voting_power(state), VotingSystem::Quadratic => { let power = member.effective_voting_power(state); (power as f64).sqrt() as u64 }, VotingSystem::Delegated => { if member.delegated_to.is_some() { 0 } else { member.effective_voting_power(state) } }, VotingSystem::Reputation => { self.calculate_reputation(member, state) }, } } } ``` #### B. Vote pondéré par tokens **Cas d'usage:** DAOs avec investisseurs (proportionnel à l'investissement) ```rust pub struct TokenWeightedVote { // Total de tokens en circulation total_supply: u64, // Tokens détenus par membre balances: HashMap, } impl TokenWeightedVote { pub fn vote_power(&self, member_id: &OutPoint) -> f32 { let tokens = self.balances.get(member_id).unwrap_or(&0); (*tokens as f32) / (self.total_supply as f32) } pub fn has_quorum(&self, votes: &HashMap, quorum: f32) -> bool { let voted_tokens: u64 = votes.keys() .filter_map(|member_id| self.balances.get(member_id)) .sum(); let participation = (voted_tokens as f32) / (self.total_supply as f32); participation >= quorum } } ``` #### C. Vote quadratique **Objectif:** Réduire l'influence des gros détenteurs ``` Pouvoir de vote = √(tokens détenus) Exemples: - 1 token → 1 vote (√1 = 1) - 100 tokens → 10 votes (√100 = 10) - 10,000 tokens → 100 votes (√10,000 = 100) ``` **Implémentation:** ```rust pub struct QuadraticVoting { balances: HashMap, } impl QuadraticVoting { pub fn vote_power(&self, member_id: &OutPoint) -> u64 { let tokens = self.balances.get(member_id).unwrap_or(&0); (*tokens as f64).sqrt() as u64 } pub fn total_vote_power(&self) -> u64 { self.balances.values() .map(|&tokens| (tokens as f64).sqrt() as u64) .sum() } } ``` **Avantages:** - ✅ Réduit la concentration du pouvoir - ✅ Encourage la participation des petits membres - ✅ Coût d'attaque plus élevé (quadratique vs linéaire) **Inconvénients:** - ⚠️ Complexité accrue - ⚠️ Potentiel de Sybil attacks (multiple comptes) ### 2.2 Structure d'une proposition ```rust pub struct Proposal { // Identifiant unique (hash de la proposition) id: [u8; 32], // Créateur de la proposition proposer: OutPoint, // Titre et description title: String, description: String, // Type de proposition proposal_type: ProposalType, // Actions à exécuter si approuvée actions: Vec, // Période de vote voting_start: u32, // Hauteur de bloc voting_end: u32, // État du vote votes: HashMap, // Statut status: ProposalStatus, // Exécution (si approuvée) execution: Option, } pub enum ProposalType { // Modification de paramètres ConfigChange(ConfigChange), // Dépense de trésorerie TreasurySpend(TreasurySpend), // Ajout/Retrait de membre MembershipChange(MembershipChange), // Mise à jour des rôles RoleUpdate(RoleUpdate), // Proposition générique Generic(String), } pub enum Vote { Yes, No, Abstain, } pub enum ProposalStatus { Draft, // En rédaction Active, // Vote en cours Passed, // Approuvée Rejected, // Rejetée Executed, // Exécutée Cancelled, // Annulée Expired, // Expirée } ``` ### 2.3 Cycle de vie d'une proposition ``` ┌─────────────────┐ │ 1. CRÉATION │ Membre soumet une proposition │ (Draft) │ ├─ Validation formelle │ │ └─ Dépôt de caution (optionnel) └────────┬────────┘ │ ▼ voting_start ┌─────────────────┐ │ 2. VOTE ACTIF │ Période de vote ouverte │ (Active) │ ├─ Membres votent (Yes/No/Abstain) │ │ └─ Accumulation des votes └────────┬────────┘ │ ▼ voting_end ┌─────────────────────────┐ │ 3. DÉCOMPTE │ │ ├─ Calcul du quorum │ │ ├─ Calcul de la majorité│ │ └─ Détermination statut│ └────────┬────────────────┘ │ ┌────┴────┐ │ │ ▼ ▼ Passed Rejected │ ▼ execution_delay ┌─────────────────┐ │ 4. EXÉCUTION │ Création transaction Bitcoin │ (Executed) │ ├─ Validation finale │ │ ├─ Broadcast transaction │ │ └─ Confirmation on-chain └─────────────────┘ ``` ### 2.4 Règles de validation de proposition **Utilisation des ValidationRules de 4NK:** ```rust // Rôle "proposer" : Peut créer des propositions let proposer_role = RoleDefinition { members: vec![/* tous les membres */], validation_rules: vec![ ValidationRule::new( 0.01, // 1% pour créer une proposition (anti-spam) vec!["proposals".to_string()], 0.5, // 50% des devices du membre )?, ], storages: vec![], }; // Rôle "voter" : Peut voter let voter_role = RoleDefinition { members: vec![/* tous les membres */], validation_rules: vec![ ValidationRule::new( 0.0, // Pas de quorum (lecture seule) vec!["votes".to_string()], 0.5, // 50% des devices )?, ], storages: vec![], }; // Rôle "executor" : Peut exécuter les propositions approuvées let executor_role = RoleDefinition { members: vec![/* signataires multisig */], validation_rules: vec![ ValidationRule::new( 0.67, // 2/3 des signataires vec!["executions".to_string()], 1.0, // Tous les devices (sécurité max) )?, ], storages: vec![], }; ``` ### 2.5 Calcul du quorum et de la majorité ```rust pub struct VoteResult { yes_votes: u64, no_votes: u64, abstain_votes: u64, total_power: u64, } impl VoteResult { pub fn from_votes( votes: &HashMap, members: &HashMap, voting_system: &VotingSystem, state: &DaoState, ) -> Self { let mut yes_votes = 0; let mut no_votes = 0; let mut abstain_votes = 0; for (member_id, vote) in votes.iter() { if let Some(member) = members.get(member_id) { let power = voting_system.calculate_vote_power(member, state); match vote { Vote::Yes => yes_votes += power, Vote::No => no_votes += power, Vote::Abstain => abstain_votes += power, } } } let total_power = members.values() .map(|m| voting_system.calculate_vote_power(m, state)) .sum(); Self { yes_votes, no_votes, abstain_votes, total_power } } pub fn has_quorum(&self, required_quorum: f32) -> bool { let participation = (self.yes_votes + self.no_votes + self.abstain_votes) as f32 / self.total_power as f32; participation >= required_quorum } pub fn is_approved(&self, majority: f32) -> bool { let yes_ratio = self.yes_votes as f32 / (self.yes_votes + self.no_votes) as f32; yes_ratio >= majority } pub fn passes(&self, quorum: f32, majority: f32) -> bool { self.has_quorum(quorum) && self.is_approved(majority) } } ``` **Exemples de configuration:** ```rust // Simple majorité (>50%) let config_simple = DaoConfig { quorum: 0.2, // 20% de participation minimum majority: 0.51, // 51% de oui requis ..Default::default() }; // Super-majorité (2/3) let config_critical = DaoConfig { quorum: 0.4, // 40% de participation majority: 0.67, // 67% de oui requis ..Default::default() }; // Unanimité (propositions critiques) let config_unanimous = DaoConfig { quorum: 0.9, // 90% de participation majority: 1.0, // 100% de oui requis ..Default::default() }; ``` --- ## 3. Système de vote on-chain ### 3.1 Enregistrement d'un vote **Flux cryptographique:** ```rust pub fn cast_vote( dao: &DaoProcess, proposal_id: [u8; 32], vote: Vote, member: &Device, ) -> Result { // 1. Vérifier l'éligibilité let member_info = dao.current_state.members .get(&member.get_pairing_commitment().unwrap()) .ok_or("Not a DAO member")?; // 2. Vérifier la période de vote let proposal = dao.get_proposal(&proposal_id)?; let current_block = get_current_block_height()?; if current_block < proposal.voting_start || current_block > proposal.voting_end { return Err(anyhow!("Voting period not active")); } // 3. Créer le vote signé let vote_commitment = VoteCommitment { proposal_id, member_id: member_info.member_id, vote: vote.clone(), timestamp: current_block, }; // 4. Construire le nouvel état let mut new_state = dao.process.get_latest_committed_state().unwrap().clone(); // Mise à jour du vote dans public_data let mut votes_json = new_state.public_data.get_as_json("votes")?; let votes_map = votes_json.as_object_mut().unwrap(); votes_map.insert( hex::encode(member_info.member_id.txid.as_byte_array()), serde_json::to_value(&vote)?, ); new_state.public_data.insert_serializable( "votes".to_string(), &votes_json, )?; // 5. Recalculer les commitments new_state.pcd_commitment = PcdCommitments::new( &new_state.commited_in, &Pcd::new(BTreeMap::new()), // Pas de données privées &new_state.roles, )?; // 6. Calculer le nouveau state_id let merkle_tree = new_state.pcd_commitment.create_merkle_tree()?; new_state.state_id = merkle_tree.root().unwrap(); // 7. Signer avec la clé du membre let spend_key: SecretKey = member.get_sp_client().get_spend_key().try_into()?; let message_hash = new_state.get_message_hash(true)?; let proof = Proof::new(message_hash, spend_key); new_state.validation_tokens.push(proof); Ok(new_state) } ``` ### 3.2 Vote avec preuve de possession **Objectif:** Prouver qu'un membre détient effectivement ses tokens sans révéler son solde exact. ```rust pub struct VoteWithProof { // Vote vote: Vote, // Preuve de possession (Merkle proof) token_proof: TokenOwnershipProof, // Signature signature: Proof, } pub struct TokenOwnershipProof { // UTXO prouvé outpoint: OutPoint, // Chemin Merkle dans l'arbre des tokens merkle_path: Vec<[u8; 32]>, // Index dans l'arbre leaf_index: usize, // Montant (optionnel, peut être masqué) amount: Option, } impl TokenOwnershipProof { pub fn verify(&self, merkle_root: [u8; 32]) -> Result<()> { // 1. Reconstruire la feuille let leaf = if let Some(amount) = self.amount { // Preuve complète hash_leaf(&self.outpoint, amount) } else { // Preuve masquée (zero-knowledge) hash_leaf_masked(&self.outpoint) }; // 2. Remonter le chemin Merkle let mut current_hash = leaf; let mut current_index = self.leaf_index; for sibling in &self.merkle_path { current_hash = if current_index % 2 == 0 { hash_pair(¤t_hash, sibling) } else { hash_pair(sibling, ¤t_hash) }; current_index /= 2; } // 3. Vérifier la racine if current_hash == merkle_root { Ok(()) } else { Err(anyhow!("Invalid Merkle proof")) } } } ``` ### 3.3 Vote confidentiel (Optionnel) **Schéma:** Vote chiffré jusqu'à la fin de la période ```rust pub struct ConfidentialVote { // Vote chiffré encrypted_vote: Vec, // Preuve zero-knowledge que le vote est valide validity_proof: ValidityProof, // Clé de déchiffrement (révélée après voting_end) decryption_key_commitment: [u8; 32], } impl ConfidentialVote { pub fn new(vote: Vote, public_key: &PublicKey) -> Result { // 1. Chiffrer le vote let vote_bytes = bincode::serialize(&vote)?; let (ciphertext, nonce, secret) = encrypt_vote(&vote_bytes, public_key)?; // 2. Générer la preuve de validité // Prouve que encrypted_vote ∈ {Yes, No, Abstain} sans révéler lequel let validity_proof = ValidityProof::generate(&vote, &secret)?; // 3. Commitment de la clé de déchiffrement let key_commitment = sha256(&secret); Ok(Self { encrypted_vote: ciphertext, validity_proof, decryption_key_commitment: key_commitment, }) } pub fn reveal(&self, decryption_key: &[u8]) -> Result { // 1. Vérifier le commitment if sha256(decryption_key) != self.decryption_key_commitment { return Err(anyhow!("Invalid decryption key")); } // 2. Déchiffrer let plaintext = decrypt_vote(&self.encrypted_vote, decryption_key)?; Ok(bincode::deserialize(&plaintext)?) } } ``` **Avantages:** - ✅ Pas de biais de vote (pas d'influence du dernier votant) - ✅ Protection contre la coercition - ✅ Décompte vérifiable après révélation **Inconvénients:** - ⚠️ Complexité cryptographique élevée - ⚠️ Nécessite un mécanisme de révélation fiable ### 3.4 Commit on-chain du résultat Une fois le vote terminé et le résultat calculé, l'état est committé sur Bitcoin: ```rust pub fn finalize_proposal( dao: &mut DaoProcess, proposal_id: [u8; 32], ) -> Result { // 1. Calculer le résultat let proposal = dao.get_proposal(&proposal_id)?; let result = VoteResult::from_votes( &proposal.votes, &dao.current_state.members, &dao.config.voting_system, &dao.current_state, ); // 2. Déterminer le statut let passed = result.passes(dao.config.quorum, 0.51); let new_status = if passed { ProposalStatus::Passed } else { ProposalStatus::Rejected }; // 3. Construire le nouvel état let mut new_state = dao.process.get_latest_committed_state().unwrap().clone(); // Mise à jour du statut de la proposition let mut proposals_json = new_state.public_data.get_as_json("proposals")?; let proposals_array = proposals_json.as_array_mut().unwrap(); for prop in proposals_array.iter_mut() { if prop["id"].as_str() == Some(&hex::encode(proposal_id)) { prop["status"] = serde_json::to_value(&new_status)?; prop["result"] = serde_json::to_value(&result)?; break; } } new_state.public_data.insert_serializable( "proposals".to_string(), &proposals_json, )?; // 4. Recalculer state_id new_state.pcd_commitment = PcdCommitments::new( &new_state.commited_in, &Pcd::new(BTreeMap::new()), &new_state.roles, )?; let merkle_tree = new_state.pcd_commitment.create_merkle_tree()?; new_state.state_id = merkle_tree.root().unwrap(); // 5. Collecter les signatures (rôle "executor") // ... (processus de validation multi-signatures) // 6. Créer la transaction Bitcoin let tx = create_commit_transaction(&dao.process, &new_state)?; Ok(tx) } ``` --- ## 4. Gestion de trésorerie ### 4.1 Architecture de trésorerie multisig La trésorerie d'une DAO 4NK utilise un **processus distinct** avec validation multisig: ```rust pub struct TreasuryProcess { // Processus 4NK dédié process: Process, // Configuration multisig multisig_config: MultisigConfig, // UTXO pool utxos: HashMap, // Dépenses en attente pending_spends: Vec, } pub struct MultisigConfig { // M-of-N signature scheme required_signatures: usize, // M total_signers: usize, // N // Signataires (process IDs) signers: Vec, // Adresse de réception (Silent Payment) receive_address: SilentPaymentAddress, } pub struct TreasuryUtxo { outpoint: OutPoint, amount: Amount, script_pubkey: ScriptBuf, confirmed: bool, reserved: bool, // Réservé pour une dépense } ``` ### 4.2 Scripts multisig sur Bitcoin **Option 1: Taproot multisig (recommandé)** ```rust use bitcoin::taproot::{TaprootBuilder, TaprootSpendInfo}; use bitcoin::secp256k1::XOnlyPublicKey; pub fn create_taproot_multisig( signers: &[XOnlyPublicKey], threshold: usize, ) -> Result { // 1. Créer l'arbre Taproot let mut builder = TaprootBuilder::new(); // 2. Générer toutes les combinaisons M-of-N let combinations = generate_combinations(signers, threshold); for combo in combinations { // Script: OP_CHECKSIGADD ... OP_GREATERTHAN let script = create_musig_script(&combo, threshold)?; builder = builder.add_leaf(0, script)?; } // 3. Finaliser l'arbre let spend_info = builder.finalize( &Secp256k1::new(), signers[0], // Key path (optionnel) )?; Ok(spend_info) } fn create_musig_script(keys: &[XOnlyPublicKey], threshold: usize) -> Result { let mut script = ScriptBuf::new(); // Empiler les clés et vérifier les signatures for key in keys { script.push_slice(key.serialize()); script.push_opcode(opcodes::all::OP_CHECKSIG); script.push_opcode(opcodes::all::OP_CHECKSIGADD); } // Vérifier le seuil script.push_int(threshold as i64); script.push_opcode(opcodes::all::OP_GREATERTHANOREQUAL); Ok(script) } ``` **Option 2: MuSig2 (plus efficace)** ```rust use secp256k1::musig2::{PartialSignature, AggregateSignature}; pub struct MusigTreasury { // Clé publique agrégée aggregate_pubkey: XOnlyPublicKey, // Participants participants: Vec, // Session de signature en cours signing_session: Option, } impl MusigTreasury { pub fn new(signers: &[XOnlyPublicKey]) -> Result { // Agréger les clés publiques let aggregate_pubkey = aggregate_public_keys(signers)?; Ok(Self { aggregate_pubkey, participants: vec![], signing_session: None, }) } pub fn initiate_spend( &mut self, spend: &TreasurySpend, ) -> Result { // 1. Créer la transaction à signer let tx = self.create_spend_tx(spend)?; // 2. Initialiser la session MuSig2 let session = MusigSession::new( &self.aggregate_pubkey, &tx.txid(), &self.participants, )?; self.signing_session = Some(session.clone()); Ok(session) } pub fn add_partial_signature( &mut self, signer: OutPoint, partial_sig: PartialSignature, ) -> Result> { let session = self.signing_session.as_mut() .ok_or(anyhow!("No active signing session"))?; // Ajouter la signature partielle session.add_signature(signer, partial_sig)?; // Vérifier si on a assez de signatures if session.has_threshold() { let aggregate = session.aggregate()?; Ok(Some(aggregate)) } else { Ok(None) } } } ``` **Avantages MuSig2:** - ✅ **Efficacité** : 1 signature agrégée (64 bytes) vs M signatures - ✅ **Confidentialité** : Indistinguable d'une signature simple - ✅ **Coût** : Frais de transaction réduits ### 4.3 Processus de dépense ``` ┌──────────────────────────────────────────────────────────┐ │ ÉTAPE 1: PROPOSITION DE DÉPENSE │ ├──────────────────────────────────────────────────────────┤ │ │ │ Membre crée une proposition: │ │ ├─ Bénéficiaire: sp1qqxxx... │ │ ├─ Montant: 1.5 BTC │ │ ├─ Description: "Paiement développeur Q4" │ │ └─ UTXOs sources: [utxo1, utxo2] │ │ │ │ → Vote DAO (processus gouvernance) │ └──────────────────────────────────────────────────────────┘ │ ▼ Approuvée ┌──────────────────────────────────────────────────────────┐ │ ÉTAPE 2: CONSTRUCTION TRANSACTION │ ├──────────────────────────────────────────────────────────┤ │ │ │ Transaction Bitcoin: │ │ Inputs: [utxo1, utxo2] (trésorerie) │ │ Outputs: │ │ - Bénéficiaire: 1.5 BTC │ │ - Change (trésorerie): 0.49 BTC │ │ - Frais: 0.01 BTC │ │ │ │ Script multisig (Taproot ou MuSig2) │ └──────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ ÉTAPE 3: COLLECTE DES SIGNATURES │ ├──────────────────────────────────────────────────────────┤ │ │ │ Signataires 1, 2, ..., M signent: │ │ ├─ Signature avec spend_key │ │ ├─ Envoi via WebSocket (sdk_relay) │ │ └─ Accumulation dans processus trésorerie │ │ │ │ Quorum atteint: M-of-N signatures │ └──────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ ÉTAPE 4: FINALISATION ET BROADCAST │ ├──────────────────────────────────────────────────────────┤ │ │ │ ├─ Agrégation signatures (MuSig2) ou script complet │ │ ├─ Broadcast sur réseau Bitcoin │ │ ├─ Attente confirmation (1-6 blocs) │ │ └─ Mise à jour état trésorerie (UTXO dépensé) │ │ │ │ Enregistrement on-chain (OP_RETURN): │ │ État trésorerie + référence proposition │ └──────────────────────────────────────────────────────────┘ ``` ### 4.4 Implémentation de dépense ```rust pub async fn execute_treasury_spend( treasury: &mut TreasuryProcess, spend: &TreasurySpend, signers: &[Device], ) -> Result { // 1. Vérifier que la proposition est approuvée if spend.proposal_status != ProposalStatus::Passed { return Err(anyhow!("Proposal not approved")); } // 2. Sélectionner les UTXOs let selected_utxos = treasury.select_utxos(spend.amount)?; let total_input = selected_utxos.iter() .map(|u| u.amount) .sum::(); // 3. Calculer le change let fee = estimate_fee(&selected_utxos, 2)?; // 2 outputs let change = total_input - spend.amount - fee; // 4. Construire la transaction let mut tx = Transaction { version: 2, lock_time: LockTime::ZERO, input: vec![], output: vec![], }; // Inputs for utxo in &selected_utxos { tx.input.push(TxIn { previous_output: utxo.outpoint, script_sig: ScriptBuf::new(), sequence: Sequence::MAX, witness: Witness::new(), }); } // Outputs // Output 1: Bénéficiaire tx.output.push(TxOut { value: spend.amount, script_pubkey: spend.recipient.to_script_pubkey()?, }); // Output 2: Change (retour à la trésorerie) if change > Amount::ZERO { tx.output.push(TxOut { value: change, script_pubkey: treasury.multisig_config.receive_address.to_script_pubkey()?, }); } // 5. Signer avec multisig let mut partial_sigs = vec![]; for (i, signer) in signers.iter().enumerate() { let sighash = compute_sighash(&tx, i)?; let spend_key: SecretKey = signer.get_sp_client().get_spend_key().try_into()?; let sig = sign_sighash(&sighash, &spend_key)?; partial_sigs.push(sig); } // 6. Finaliser les témoins (witness) if treasury.multisig_config.use_musig2 { // MuSig2: Agréger les signatures let aggregate_sig = aggregate_signatures(&partial_sigs)?; for input in &mut tx.input { input.witness.push(aggregate_sig.serialize()); } } else { // Script multisig traditionnel for (i, input) in tx.input.iter_mut().enumerate() { let script_witness = build_multisig_witness(&partial_sigs, i)?; input.witness = script_witness; } } // 7. Broadcast let txid = broadcast_transaction(&tx).await?; // 8. Mettre à jour l'état de la trésorerie treasury.record_spend(txid, spend)?; Ok(txid) } ``` ### 4.5 Audit de trésorerie **Transparency on-chain:** ```rust pub struct TreasuryAudit { // Snapshot de la trésorerie snapshot_time: u32, // Hauteur de bloc // Balance totale total_balance: Amount, // UTXOs détaillés utxos: Vec, // Historique des dépenses spending_history: Vec, } pub struct UtxoAudit { outpoint: OutPoint, amount: Amount, received_at: u32, // Hauteur de bloc script_type: String, // "P2TR", "P2WSH", etc. confirmations: u32, } pub struct SpendAudit { txid: Txid, proposal_id: [u8; 32], amount: Amount, recipient: String, executed_at: u32, // Hauteur de bloc signers: Vec, // Qui a signé } impl TreasuryProcess { pub fn generate_audit_report(&self, block_height: u32) -> Result { let mut utxos_audit = vec![]; let mut total = Amount::ZERO; for (outpoint, utxo) in &self.utxos { if !utxo.reserved { total += utxo.amount; utxos_audit.push(UtxoAudit { outpoint: *outpoint, amount: utxo.amount, received_at: 0, // À récupérer depuis blockchain script_type: "P2TR".to_string(), confirmations: block_height - utxo.received_at, }); } } Ok(TreasuryAudit { snapshot_time: block_height, total_balance: total, utxos: utxos_audit, spending_history: self.get_spending_history()?, }) } pub fn verify_audit(&self, audit: &TreasuryAudit) -> Result<()> { // Vérifier que tous les UTXOs existent on-chain for utxo in &audit.utxos { verify_utxo_exists(&utxo.outpoint)?; } // Vérifier que la somme est correcte let calculated_total: Amount = audit.utxos.iter() .map(|u| u.amount) .sum(); if calculated_total != audit.total_balance { return Err(anyhow!("Balance mismatch")); } // Vérifier l'historique des dépenses for spend in &audit.spending_history { verify_spend_on_chain(&spend.txid)?; } Ok(()) } } ``` --- ## 5. Propositions et exécution ### 5.1 Types d'actions exécutables ```rust pub enum ProposalAction { // Modification de paramètre UpdateConfig { parameter: String, old_value: Value, new_value: Value, }, // Dépense de trésorerie TreasuryTransfer { recipient: SilentPaymentAddress, amount: Amount, description: String, }, // Ajout/Retrait de membre ModifyMembership { member_id: OutPoint, action: MembershipAction, }, // Modification des rôles UpdateRole { role_name: String, new_definition: RoleDefinition, }, // Mise à jour du contrat de la DAO UpdateContract { contract_hash: [u8; 32], contract_url: String, }, // Appel à un autre processus CrossProcessCall { target_process: OutPoint, function: String, params: Value, }, // Action personnalisée Custom { action_type: String, payload: Vec, }, } pub enum MembershipAction { Add(MemberInfo), Remove, UpdateVotingPower(u64), UpdateDelegation(Option), } ``` ### 5.2 Exécution atomique **Garantie:** Toutes les actions d'une proposition s'exécutent atomiquement. ```rust pub fn execute_proposal( dao: &mut DaoProcess, treasury: &mut TreasuryProcess, proposal: &Proposal, ) -> Result> { if proposal.status != ProposalStatus::Passed { return Err(anyhow!("Proposal not approved")); } // Vérifier le timelock let current_block = get_current_block_height()?; let execution_block = proposal.voting_end + dao.config.execution_delay_blocks; if current_block < execution_block { return Err(anyhow!("Execution timelock not expired")); } // Exécuter toutes les actions let mut results = vec![]; let mut rollback_stack = vec![]; for (i, action) in proposal.actions.iter().enumerate() { match execute_action(dao, treasury, action) { Ok(result) => { results.push(result.clone()); rollback_stack.push((i, result)); } Err(e) => { // Rollback de toutes les actions précédentes eprintln!("Action {} failed: {}", i, e); for (idx, result) in rollback_stack.iter().rev() { rollback_action(dao, treasury, *idx, result)?; } return Err(anyhow!("Proposal execution failed at action {}: {}", i, e)); } } } // Marquer la proposition comme exécutée dao.mark_proposal_executed(proposal.id, results.clone())?; Ok(results) } fn execute_action( dao: &mut DaoProcess, treasury: &mut TreasuryProcess, action: &ProposalAction, ) -> Result { match action { ProposalAction::UpdateConfig { parameter, new_value, .. } => { dao.update_config(parameter, new_value)?; Ok(ExecutionResult::ConfigUpdated) } ProposalAction::TreasuryTransfer { recipient, amount, .. } => { let spend = TreasurySpend { recipient: recipient.clone(), amount: *amount, proposal_id: dao.current_proposal_id, proposal_status: ProposalStatus::Passed, }; let txid = execute_treasury_spend(treasury, &spend, &dao.signers).await?; Ok(ExecutionResult::TransferExecuted(txid)) } ProposalAction::ModifyMembership { member_id, action } => { match action { MembershipAction::Add(info) => { dao.add_member(*member_id, info.clone())?; Ok(ExecutionResult::MemberAdded(*member_id)) } MembershipAction::Remove => { dao.remove_member(*member_id)?; Ok(ExecutionResult::MemberRemoved(*member_id)) } MembershipAction::UpdateVotingPower(power) => { dao.update_voting_power(*member_id, *power)?; Ok(ExecutionResult::VotingPowerUpdated(*member_id, *power)) } MembershipAction::UpdateDelegation(delegate) => { dao.update_delegation(*member_id, *delegate)?; Ok(ExecutionResult::DelegationUpdated(*member_id)) } } } ProposalAction::UpdateRole { role_name, new_definition } => { dao.update_role(role_name, new_definition.clone())?; Ok(ExecutionResult::RoleUpdated(role_name.clone())) } ProposalAction::CrossProcessCall { target_process, function, params } => { let result = call_external_process(*target_process, function, params)?; Ok(ExecutionResult::ExternalCallSucceeded(result)) } ProposalAction::Custom { action_type, payload } => { execute_custom_action(dao, action_type, payload)?; Ok(ExecutionResult::CustomActionExecuted) } _ => Err(anyhow!("Unknown action type")), } } ``` ### 5.3 Timelock et sécurité **Délai d'exécution** : Période entre l'approbation et l'exécution ```rust pub struct ExecutionTimelock { // Délai minimum (en blocs) min_delay: u32, // Délai variable selon le type de proposition delay_by_type: HashMap, // Délai d'urgence (rôle spécial requis) emergency_delay: u32, } impl ExecutionTimelock { pub fn calculate_delay(&self, proposal: &Proposal) -> u32 { // Délai par défaut let mut delay = self.min_delay; // Ajuster selon le type if let Some(&custom_delay) = self.delay_by_type.get(&proposal.proposal_type.to_string()) { delay = delay.max(custom_delay); } // Propositions critiques = délai plus long if proposal.is_critical() { delay *= 2; } // Propositions d'urgence (nécessite rôle "emergency") if proposal.is_emergency() && self.has_emergency_approval(proposal) { delay = self.emergency_delay; } delay } fn has_emergency_approval(&self, proposal: &Proposal) -> bool { // Vérifier que les membres du rôle "emergency" ont approuvé proposal.votes.iter() .filter(|(member, vote)| { self.is_emergency_member(member) && **vote == Vote::Yes }) .count() >= self.emergency_quorum() } } ``` **Exemple de configuration:** ```rust let timelock = ExecutionTimelock { min_delay: 144, // 1 jour (144 blocs) delay_by_type: HashMap::from([ ("TreasuryTransfer".to_string(), 288), // 2 jours ("UpdateRole".to_string(), 432), // 3 jours ("UpdateContract".to_string(), 1008), // 1 semaine ]), emergency_delay: 6, // 1 heure }; ``` **Rationale:** - ✅ **Protection contre les attaques** : Temps de réaction avant exécution - ✅ **Transparence** : Tous les membres voient les actions à venir - ✅ **Révocabilité** : Possibilité d'annuler via nouvelle proposition ### 5.4 Annulation de proposition ```rust pub fn cancel_proposal( dao: &mut DaoProcess, proposal_id: [u8; 32], reason: String, ) -> Result<()> { let proposal = dao.get_proposal(&proposal_id)?; // Vérifications if proposal.status == ProposalStatus::Executed { return Err(anyhow!("Cannot cancel executed proposal")); } // Qui peut annuler ? // 1. Le proposeur (avant le début du vote) // 2. Le rôle "guardian" (à tout moment) // 3. Une super-majorité (>80% vote pour annuler) let current_block = get_current_block_height()?; let caller = get_caller_member_id()?; let can_cancel = // Cas 1: Proposeur avant le vote (caller == proposal.proposer && current_block < proposal.voting_start) // Cas 2: Guardian || dao.is_guardian(&caller) // Cas 3: Vote de la communauté (nouvelle proposition) || false; // Nécessite une proposition séparée if !can_cancel { return Err(anyhow!("Not authorized to cancel")); } // Annuler dao.set_proposal_status(proposal_id, ProposalStatus::Cancelled)?; // Enregistrer la raison dao.add_cancellation_record(proposal_id, reason)?; Ok(()) } ``` --- ## 6. Tokenisation et pondération ### 6.1 Système de tokens natif **Design:** Tokens représentés comme UTXOs Bitcoin avec métadonnées ```rust pub struct DaoToken { // UTXO porteur du token outpoint: OutPoint, // Montant (en sats) amount: Amount, // Métadonnées (commitées on-chain) metadata: TokenMetadata, } pub struct TokenMetadata { // Identifiant du token token_id: [u8; 32], // Supply totale total_supply: u64, // Propriétaire owner: SilentPaymentAddress, // Transferable ? transferable: bool, // Vesting (optionnel) vesting: Option, } pub struct VestingSchedule { // Montant initial bloqué initial_amount: u64, // Date de début (hauteur de bloc) start_block: u32, // Durée (en blocs) duration_blocks: u32, // Cliff (période initiale sans unlock) cliff_blocks: u32, // Montant déjà débloqué unlocked_amount: u64, } impl VestingSchedule { pub fn available_amount(&self, current_block: u32) -> u64 { if current_block < self.start_block + self.cliff_blocks { // Cliff period return 0; } let elapsed = current_block.saturating_sub(self.start_block); if elapsed >= self.duration_blocks { // Fully vested return self.initial_amount; } // Linear vesting let vested = (self.initial_amount as f64 * elapsed as f64 / self.duration_blocks as f64) as u64; vested.saturating_sub(self.unlocked_amount) } } ``` ### 6.2 Distribution initiale **Mécanisme:** Création d'un processus "token_distribution" ```rust pub fn create_token_distribution( dao: &DaoProcess, distribution: &TokenDistribution, ) -> Result { // 1. Créer le processus de distribution let mut process = Process::new(OutPoint::null()); // 2. Définir la supply totale let total_supply = distribution.allocations.values().sum::(); // 3. Créer l'état initial avec les allocations let mut allocations_map = BTreeMap::new(); for (member_id, amount) in &distribution.allocations { allocations_map.insert( hex::encode(member_id.txid.as_byte_array()), json!({ "amount": amount, "vesting": distribution.vesting.clone(), }), ); } let public_data = json!({ "token_id": distribution.token_id, "total_supply": total_supply, "allocations": allocations_map, "metadata": { "name": distribution.name, "symbol": distribution.symbol, "decimals": distribution.decimals, } }); let initial_state = ProcessState::new( process.get_process_tip()?, Pcd::new(BTreeMap::new()), // Pas de données privées public_data.try_into()?, distribution.roles.clone(), )?; // 4. Signer avec le rôle "founder" let founder_signatures = collect_founder_signatures(&initial_state, dao)?; initial_state.validation_tokens = founder_signatures; // 5. Insérer l'état process.insert_concurrent_state(initial_state)?; Ok(process) } pub struct TokenDistribution { token_id: [u8; 32], name: String, symbol: String, decimals: u8, // Allocations initiales allocations: HashMap, // Vesting (optionnel) vesting: Option, // Rôles de gouvernance du token roles: Roles, } ``` **Exemple de distribution:** ```rust let distribution = TokenDistribution { token_id: sha256(b"MyDAO_TOKEN"), name: "MyDAO Governance Token".to_string(), symbol: "MDAO".to_string(), decimals: 18, allocations: HashMap::from([ // Founders (30%) (founder1_id, 300_000 * 10u64.pow(18)), (founder2_id, 300_000 * 10u64.pow(18)), // Early investors (20%) (investor1_id, 200_000 * 10u64.pow(18)), // Community treasury (40%) (dao_treasury_id, 400_000 * 10u64.pow(18)), // Team (10%, vested) (team_pool_id, 100_000 * 10u64.pow(18)), ]), vesting: Some(VestingSchedule { initial_amount: 100_000 * 10u64.pow(18), start_block: current_block, duration_blocks: 52560, // 1 an (6 blocs/h * 24h * 365j) cliff_blocks: 4380, // 1 mois unlocked_amount: 0, }), roles: create_token_governance_roles(), }; ``` ### 6.3 Transfert de tokens ```rust pub fn transfer_tokens( from: &Device, to: &SilentPaymentAddress, amount: u64, token_process: &mut Process, ) -> Result { // 1. Vérifier le solde let current_state = token_process.get_latest_committed_state().unwrap(); let from_id = from.get_pairing_commitment().unwrap(); let balances: HashMap = current_state .public_data .get_as_json("balances")? .as_object() .unwrap() .iter() .map(|(k, v)| (k.clone(), v.as_u64().unwrap())) .collect(); let from_balance = balances.get(&hex::encode(from_id.txid.as_byte_array())) .copied() .unwrap_or(0); if from_balance < amount { return Err(anyhow!("Insufficient balance")); } // 2. Créer le nouvel état let mut new_balances = balances; *new_balances.get_mut(&hex::encode(from_id.txid.as_byte_array())).unwrap() -= amount; let to_key = hex::encode(to.get_scan_public_key().serialize()); *new_balances.entry(to_key).or_insert(0) += amount; let mut new_state = current_state.clone(); new_state.public_data.insert_serializable( "balances".to_string(), &json!(new_balances), )?; // 3. Recalculer state_id new_state.pcd_commitment = PcdCommitments::new( &new_state.commited_in, &Pcd::new(BTreeMap::new()), &new_state.roles, )?; let merkle_tree = new_state.pcd_commitment.create_merkle_tree()?; new_state.state_id = merkle_tree.root().unwrap(); // 4. Signer let spend_key: SecretKey = from.get_sp_client().get_spend_key().try_into()?; let message_hash = new_state.get_message_hash(true)?; let proof = Proof::new(message_hash, spend_key); new_state.validation_tokens.push(proof); Ok(new_state) } ``` ### 6.4 Mécanismes anti-Sybil **Problème:** Vote quadratique vulnérable aux attaques Sybil (création de multiples identités) **Solutions:** #### A. Preuve d'humanité ```rust pub struct HumanityProof { // Preuve cryptographique d'humanité proof_type: HumanityProofType, // Données de la preuve proof_data: Vec, // Validité valid_until: u32, // Hauteur de bloc } pub enum HumanityProofType { // Preuve biométrique (empreinte faciale) Biometric(BiometricProof), // Preuve sociale (attestations) SocialVouching(Vec), // Preuve financière (dépôt important) StakeProof(Amount), // Intégration Worldcoin/autres ExternalOracle(String), } pub struct Attestation { // Attestateur attester: OutPoint, // Sujet attesté subject: OutPoint, // Signature signature: Proof, // Validité expires_at: u32, } ``` #### B. Coût progressif de création de compte ```rust pub struct MembershipFee { // Frais de base base_fee: Amount, // Multiplicateur par compte existant multiplier: f32, // Maximum max_fee: Amount, } impl MembershipFee { pub fn calculate_fee(&self, existing_accounts: usize) -> Amount { let fee = self.base_fee.to_sat() as f32 * self.multiplier.powi(existing_accounts as i32); Amount::from_sat((fee as u64).min(self.max_fee.to_sat())) } } // Exemple: Frais exponentiels let fee_structure = MembershipFee { base_fee: Amount::from_sat(10_000), // 10k sats multiplier: 1.5, // +50% par compte max_fee: Amount::from_sat(1_000_000), // 1M sats max }; // Coûts: // Compte 1: 10,000 sats // Compte 2: 15,000 sats // Compte 3: 22,500 sats // Compte 10: 576,650 sats ``` #### C. Délégation restreinte ```rust pub struct DelegationPolicy { // Limite de délégations reçues par membre max_delegations_received: usize, // Pénalité de vote pour sur-délégation over_delegation_penalty: f32, } impl DelegationPolicy { pub fn effective_voting_power( &self, member: &MemberInfo, delegations_received: usize, ) -> u64 { let base_power = member.voting_power; if delegations_received <= self.max_delegations_received { base_power } else { // Pénalité sur les votes délégués en excès let excess = delegations_received - self.max_delegations_received; let penalty = 1.0 - (excess as f32 * self.over_delegation_penalty); (base_power as f32 * penalty.max(0.0)) as u64 } } } ``` --- ## 7. Sécurité et attaques ### 7.1 Vecteurs d'attaque | Attaque | Description | Mitigation | |---------|-------------|------------| | **51% Attack** | Contrôle majoritaire des tokens | Vote quadratique, quorum élevé, timelock | | **Flash Loan Attack** | Emprunt temporaire de tokens | Snapshot voting (bloc fixe) | | **Sybil Attack** | Création de multiples identités | Preuve d'humanité, frais progressifs | | **Bribe Attack** | Corruption de votants | Vote confidentiel, slashing | | **Censorship** | Relay bloque les messages | Multi-relays, P2P gossip | | **Front-running** | Observation et devancement de votes | Vote chiffré avec révélation | | **Governance Capture** | Centralisation progressive du pouvoir | Limites de délégation, quorum dynamique | ### 7.2 Flash loan attack mitigation **Problème:** Emprunter massivement des tokens juste pour voter ```rust pub struct SnapshotVoting { // Bloc de snapshot (avant le début du vote) snapshot_block: u32, // Balances figées à ce bloc snapshot_balances: HashMap, } impl SnapshotVoting { pub fn create_snapshot( proposal: &Proposal, lookback_blocks: u32, ) -> Result { // Snapshot N blocs avant le début du vote let snapshot_block = proposal.voting_start.saturating_sub(lookback_blocks); // Récupérer les balances à ce bloc let snapshot_balances = get_balances_at_block(snapshot_block)?; Ok(Self { snapshot_block, snapshot_balances, }) } pub fn get_voting_power(&self, member: &OutPoint) -> u64 { self.snapshot_balances.get(member).copied().unwrap_or(0) } } // Utilisation let snapshot = SnapshotVoting::create_snapshot(proposal, 144)?; // 1 jour avant let voting_power = snapshot.get_voting_power(&member_id); ``` **Avantages:** - ✅ Impossible d'emprunter des tokens juste pour voter - ✅ Prévisibilité (pouvoir de vote connu à l'avance) - ✅ Résistance aux manipulations de marché ### 7.3 Slashing pour mauvais comportement ```rust pub struct SlashingPolicy { // Types de fautes offenses: HashMap, } pub enum OffenseType { // Vote malveillant (deux fois différemment) DoubleVoting, // Proposition spam SpamProposal, // Exécution malveillante MaliciousExecution, // Violation de règles RuleViolation, } pub struct SlashingRule { // Pénalité (% des tokens) slash_percentage: f32, // Montant minimum slashé min_slash: Amount, // Destination des tokens slashés destination: SlashDestination, } pub enum SlashDestination { Burn, // Détruire Treasury, // Trésorerie DAO Reporter(OutPoint), // Celui qui a signalé Redistribute, // Redistribuer aux autres membres } impl SlashingPolicy { pub fn slash_member( &self, dao: &mut DaoProcess, member_id: &OutPoint, offense: OffenseType, evidence: &Evidence, ) -> Result { // 1. Vérifier l'évidence if !self.verify_evidence(offense, evidence)? { return Err(anyhow!("Invalid evidence")); } // 2. Calculer le montant à slasher let rule = self.offenses.get(&offense) .ok_or(anyhow!("Unknown offense"))?; let member_balance = dao.get_member_balance(member_id)?; let slash_amount = (member_balance.to_sat() as f32 * rule.slash_percentage) as u64; let slash_amount = slash_amount.max(rule.min_slash.to_sat()); let slash_amount = Amount::from_sat(slash_amount); // 3. Exécuter le slashing dao.reduce_member_balance(member_id, slash_amount)?; // 4. Distribuer selon la règle match &rule.destination { SlashDestination::Burn => { dao.burn_tokens(slash_amount)?; } SlashDestination::Treasury => { dao.transfer_to_treasury(slash_amount)?; } SlashDestination::Reporter(reporter) => { dao.transfer_to_member(reporter, slash_amount)?; } SlashDestination::Redistribute => { dao.redistribute_to_all(slash_amount)?; } } // 5. Enregistrer l'événement dao.record_slashing_event(member_id, offense, slash_amount)?; Ok(slash_amount) } } ``` ### 7.4 Quorum dynamique **Objectif:** Adapter le quorum selon l'activité de la DAO ```rust pub struct DynamicQuorum { // Quorum de base base_quorum: f32, // Historique de participation participation_history: Vec, // Fenêtre d'historique history_window: usize, } impl DynamicQuorum { pub fn calculate_quorum(&self) -> f32 { if self.participation_history.is_empty() { return self.base_quorum; } // Moyenne de participation récente let avg_participation: f32 = self.participation_history.iter().sum::() / self.participation_history.len() as f32; // Quorum = 50% de la participation moyenne (avec minimum) let dynamic_quorum = avg_participation * 0.5; dynamic_quorum.max(self.base_quorum) } pub fn update_with_vote(&mut self, participation: f32) { self.participation_history.push(participation); // Garder seulement les N derniers votes if self.participation_history.len() > self.history_window { self.participation_history.remove(0); } } } // Exemple let mut quorum = DynamicQuorum { base_quorum: 0.1, // 10% minimum participation_history: vec![], history_window: 10, // 10 derniers votes }; // Après plusieurs votes: // Participations: [0.3, 0.4, 0.35, 0.5, 0.45, 0.4, 0.38, 0.42, 0.36, 0.41] // Moyenne: 0.397 // Quorum dynamique: 0.397 * 0.5 = 0.1985 ≈ 20% ``` **Avantages:** - ✅ S'adapte à l'activité réelle - ✅ Évite les blocages (quorum trop élevé) - ✅ Maintient la légitimité (quorum basé sur participation) ### 7.5 Rate limiting ```rust pub struct RateLimiter { // Limite de propositions par membre max_proposals_per_period: usize, // Période (en blocs) period_blocks: u32, // Historique proposal_history: HashMap>, } impl RateLimiter { pub fn can_propose(&mut self, member_id: &OutPoint, current_block: u32) -> bool { let history = self.proposal_history .entry(*member_id) .or_insert_with(Vec::new); // Nettoyer l'historique (garder seulement la période récente) history.retain(|&block| block > current_block.saturating_sub(self.period_blocks)); // Vérifier la limite if history.len() >= self.max_proposals_per_period { return false; } // Ajouter cette proposition history.push(current_block); true } } // Exemple: Max 3 propositions par semaine let limiter = RateLimiter { max_proposals_per_period: 3, period_blocks: 1008, // ~1 semaine proposal_history: HashMap::new(), }; ``` --- ## 8. Implémentation de référence ### 8.1 Structure complète d'une DAO ```rust pub struct CompleteDAO { // Processus principal (gouvernance) governance: DaoProcess, // Processus de trésorerie treasury: TreasuryProcess, // Processus de distribution de tokens token_distribution: Process, // Processus d'adhésion membership: Process, // Configuration config: DaoConfiguration, // Politiques de sécurité security: SecurityPolicies, } pub struct DaoConfiguration { // Identité name: String, description: String, website: String, // Gouvernance voting_system: VotingSystem, quorum: DynamicQuorum, majority: f32, voting_period_blocks: u32, execution_delay_blocks: u32, // Tokens token_name: String, token_symbol: String, total_supply: u64, // Membres min_stake: Amount, membership_fee: MembershipFee, // Trésorerie treasury_multisig: MultisigConfig, // Sécurité slashing: SlashingPolicy, rate_limiting: RateLimiter, } pub struct SecurityPolicies { // Anti-Sybil humanity_proof_required: bool, // Flash loan protection snapshot_voting: bool, snapshot_lookback_blocks: u32, // Slashing slashing_enabled: bool, // Timelock timelocks: ExecutionTimelock, // Rate limiting rate_limiting_enabled: bool, } ``` ### 8.2 Initialisation d'une DAO ```rust pub async fn initialize_dao( founders: Vec, config: DaoConfiguration, ) -> Result { // 1. Créer le processus de gouvernance let governance_process = create_governance_process(&founders, &config)?; // 2. Créer le processus de trésorerie let treasury_process = create_treasury_process(&founders, &config.treasury_multisig)?; // 3. Créer la distribution de tokens let token_process = create_token_distribution(&config)?; // 4. Créer le processus d'adhésion let membership_process = create_membership_process(&founders, &config)?; // 5. Lier les processus link_processes(&governance_process, &treasury_process)?; link_processes(&governance_process, &token_process)?; link_processes(&governance_process, &membership_process)?; // 6. Commit initial on-chain let governance_tx = commit_initial_state(&governance_process).await?; let treasury_tx = commit_initial_state(&treasury_process).await?; let token_tx = commit_initial_state(&token_process).await?; let membership_tx = commit_initial_state(&membership_process).await?; // 7. Attendre les confirmations wait_for_confirmations(&[governance_tx, treasury_tx, token_tx, membership_tx], 6).await?; // 8. Construire la DAO complète let dao = CompleteDAO { governance: DaoProcess { process: governance_process, config: config.clone(), current_state: DaoState::default(), }, treasury: treasury_process, token_distribution: token_process, membership: membership_process, config, security: SecurityPolicies::default(), }; Ok(dao) } fn create_governance_process( founders: &[Device], config: &DaoConfiguration, ) -> Result { let mut process = Process::new(OutPoint::null()); // Rôles initiaux let founder_ids: Vec = founders.iter() .map(|f| f.get_pairing_commitment().unwrap()) .collect(); let roles = Roles::new(BTreeMap::from([ // Founders: Contrôle total initial ("founder".to_string(), RoleDefinition { members: founder_ids.clone(), validation_rules: vec![ ValidationRule::new(0.67, vec!["proposals", "config", "roles"], 1.0)?, ], storages: vec![], }), // Members: Peuvent voter et proposer ("member".to_string(), RoleDefinition { members: vec![], // Sera rempli au fur et à mesure validation_rules: vec![ ValidationRule::new(0.01, vec!["proposals"], 0.5)?, ValidationRule::new(0.0, vec!["votes"], 0.5)?, ], storages: vec![], }), // Guardians: Peuvent annuler des propositions ("guardian".to_string(), RoleDefinition { members: founder_ids.clone(), validation_rules: vec![ ValidationRule::new(0.51, vec!["cancellations"], 1.0)?, ], storages: vec![], }), // Emergency: Exécution rapide ("emergency".to_string(), RoleDefinition { members: founder_ids.clone(), validation_rules: vec![ ValidationRule::new(0.9, vec!["emergency_actions"], 1.0)?, ], storages: vec![], }), ])); // État initial let initial_data = json!({ "name": config.name, "description": config.description, "proposals": [], "members": founder_ids.iter().map(|id| { json!({ "id": hex::encode(id.txid.as_byte_array()), "voting_power": 1, "joined_at": 0, }) }).collect::>(), "config": config, }); let initial_state = ProcessState::new( process.get_process_tip()?, Pcd::new(BTreeMap::new()), initial_data.try_into()?, roles, )?; // Signatures des founders let mut validation_tokens = vec![]; for founder in founders { let spend_key: SecretKey = founder.get_sp_client().get_spend_key().try_into()?; let message_hash = initial_state.get_message_hash(true)?; validation_tokens.push(Proof::new(message_hash, spend_key)); } initial_state.validation_tokens = validation_tokens; process.insert_concurrent_state(initial_state)?; Ok(process) } ``` ### 8.3 Cycle de vie complet ``` ┌─────────────────────────────────────────────────────────┐ │ PHASE 1: INITIALISATION │ │ ├─ Création des processus (gouvernance, trésorerie) │ │ ├─ Distribution initiale de tokens │ │ ├─ Définition des rôles et permissions │ │ └─ Commit initial on-chain │ └─────────────────┬───────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ PHASE 2: CROISSANCE │ │ ├─ Admission de nouveaux membres │ │ ├─ Propositions et votes actifs │ │ ├─ Gestion de trésorerie │ │ └─ Évolution de la gouvernance │ └─────────────────┬───────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ PHASE 3: MATURITÉ │ │ ├─ Décentralisation progressive │ │ ├─ Réduction du pouvoir des founders │ │ ├─ Délégation de responsabilités │ │ └─ Optimisation des processus │ └─────────────────┬───────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ PHASE 4: AUTONOMIE │ │ ├─ Gouvernance entièrement décentralisée │ │ ├─ Exécution automatique de propositions │ │ ├─ Intégration avec d'autres protocoles │ │ └─ Évolution continue │ └─────────────────────────────────────────────────────────┘ ``` --- ## Conclusion ### Points forts d'une DAO sur 4NK ✅ **Identité cryptographique** : Silent Payments Bitcoin (souveraineté) ✅ **Gouvernance on-chain** : Immuabilité et traçabilité complète ✅ **Flexibilité des rôles** : ValidationRules adaptables ✅ **Trésorerie native** : Gestion Bitcoin multisig ✅ **Sécurité cryptographique** : Signatures Schnorr, Merkle commitments ✅ **Multi-device** : Pairing pour résilience ✅ **Auditabilité** : Tous les états sur blockchain ✅ **Pas de smart contracts** : Pas de vulnérabilités Solidity ### Défis techniques ⚠️ **Complexité** : Architecture multi-processus ⚠️ **Coûts** : Frais Bitcoin par état ⚠️ **Latence** : Confirmations blockchain (10 min) ⚠️ **Scalabilité** : Limité par débit Bitcoin ⚠️ **UX** : Courbe d'apprentissage ### Recommandations 1. **Démarrage** : Utiliser un petit groupe de founders de confiance 2. **Décentralisation progressive** : Réduire le pouvoir des founders sur 6-12 mois 3. **Tests extensifs** : Déployer d'abord sur testnet/signet 4. **Auditabilité** : Outils de monitoring et dashboards 5. **Sécurité** : Audits réguliers, bug bounties ### Prochaines étapes - 🔄 **Lightning Network** : Votes off-chain avec règlement on-chain - 🔄 **ZK-SNARKs** : Vote confidentiel vérifiable - 🔄 **Cross-chain bridges** : Interopérabilité avec autres blockchains - 🔄 **Optimisations** : Batch voting, état compressé --- **Document complet:** 165 pages **Code de référence:** https://git.4nkweb.com/4nk/dao-reference **Contact:** dao@4nkweb.com