main.adl
1 // ACDC Forge - Delta Chain Code Governor Voting 2 // Controls: deltavm, deltaos, DEX modules, acdc-core (shared) 3 4 program forge_delta.aleo { 5 // ============================================ 6 // CONSTANTS 7 // ============================================ 8 9 const MIN_STAKE_AMOUNT: u64 = 10000u64; // 10,000 DX minimum 10 const MAX_MISSED_VOTES: u8 = 3u8; // 3 misses = deregister 11 const VOTE_DURATION: u64 = 604800u64; // 7 days in seconds 12 const COOLDOWN_DURATION: u64 = 172800u64; // 48 hours in seconds 13 14 // ============================================ 15 // STRUCTS 16 // ============================================ 17 18 // Contributor reputation for rewards/punishment system 19 struct Contributor { 20 prs_submitted: u32, 21 prs_merged: u32, 22 prs_rejected: u32, 23 behavior_flags: u32, 24 reward_points: u64, 25 registered_at: u64 26 } 27 28 // Code Governor - 10k+ DX stakers 29 struct CodeGovernor { 30 stake_amount: u64, 31 registered_at: u64, 32 missed_votes: u8, 33 last_vote_at: u64, 34 status: u8 // 0=inactive, 1=active, 2=deregistered 35 } 36 37 // Pull Request metadata 38 struct PullRequest { 39 commit_hash: field, 40 submitter: address, 41 repo_id: field, 42 sponsor: address, 43 sponsored_at: u64, 44 vote_deadline: u64, 45 yes_votes: u32, 46 no_votes: u32, 47 status: u8, // 0=draft, 1=voting, 2=passed, 3=failed, 4=proposal_created, 5=executed 48 behavior_flags: u8, 49 governance_proposal_id: u128, // Linked governance.delta proposal 50 is_shared_repo: bool // Requires Alpha vote too 51 } 52 53 // Individual vote record 54 struct Vote { 55 pr_hash: field, 56 voter: address, 57 vote_type: u8, // 0=no, 1=yes, 2=abstain 58 flags: u8, 59 cast_at: u64 60 } 61 62 // Code checkpoint with signatures 63 struct Checkpoint { 64 commit_hash: field, 65 radicle_oid: field, 66 approver_count: u8, 67 finalized_at: u64 68 } 69 70 // Resubmission tracking 71 struct ResubmissionCooldown { 72 original_pr_hash: field, 73 failed_at: u64, 74 cooldown_until: u64, 75 submitter: address 76 } 77 78 // Cross-chain attestation for shared repos 79 struct CrossChainAttestation { 80 pr_hash: field, 81 alpha_passed: bool, 82 delta_passed: bool, 83 alpha_proposal_id: u128, 84 delta_proposal_id: u128, 85 finalized_at: u64 86 } 87 88 // ============================================ 89 // MAPPINGS (On-Chain Storage) 90 // ============================================ 91 92 mapping code_governors: address => CodeGovernor; 93 mapping pr_registry: field => PullRequest; 94 mapping votes: field => Vote; 95 mapping checkpoints: field => Checkpoint; 96 mapping contributors: address => Contributor; 97 98 // Counter for total active governors (for threshold and 50-minimum) 99 mapping governor_count: u8 => u32; 100 101 // Governance integration 102 mapping resubmission_cooldowns: field => ResubmissionCooldown; 103 mapping cross_chain_attestations: field => CrossChainAttestation; 104 mapping proposal_to_pr: u128 => field; 105 106 // Shared repo IDs (deltavm, deltaos, acdc-core, sdk, adl) 107 mapping shared_repos: field => bool; 108 109 // ============================================ 110 // TRANSITIONS 111 // ============================================ 112 113 // Register as Code Governor (requires 10k+ DX stake proof) 114 transition register_code_governor( 115 public stake_amount: u64, 116 public registered_at: u64 117 ) -> CodeGovernor { 118 // Verify minimum stake requirement 119 assert(stake_amount >= MIN_STAKE_AMOUNT); 120 121 let gov: CodeGovernor = CodeGovernor { 122 stake_amount: stake_amount, 123 registered_at: registered_at, 124 missed_votes: 0u8, 125 last_vote_at: 0u64, 126 status: 1u8 127 }; 128 129 return gov then finalize(self.caller, gov); 130 } 131 132 finalize register_code_governor( 133 gov_address: address, 134 gov: CodeGovernor 135 ) { 136 // Store the governor 137 Mapping::set(code_governors, gov_address, gov); 138 139 // Increment governor count 140 let current_count: u32 = Mapping::get_or_use(governor_count, 0u8, 0u32); 141 Mapping::set(governor_count, 0u8, current_count + 1u32); 142 } 143 144 // Deregister a Code Governor (voluntary or due to missed votes) 145 transition deregister_code_governor() -> bool { 146 return true then finalize(self.caller); 147 } 148 149 finalize deregister_code_governor(gov_address: address) { 150 let gov: CodeGovernor = Mapping::get(code_governors, gov_address); 151 152 let updated_gov: CodeGovernor = CodeGovernor { 153 stake_amount: gov.stake_amount, 154 registered_at: gov.registered_at, 155 missed_votes: gov.missed_votes, 156 last_vote_at: gov.last_vote_at, 157 status: 2u8 // deregistered 158 }; 159 160 Mapping::set(code_governors, gov_address, updated_gov); 161 162 // Decrement governor count 163 let current_count: u32 = Mapping::get(governor_count, 0u8); 164 Mapping::set(governor_count, 0u8, current_count - 1u32); 165 } 166 167 // Submit a new PR (registers it on-chain) 168 transition submit_pr( 169 public commit_hash: field, 170 public repo_id: field, 171 public submitted_at: u64, 172 public is_shared_repo: bool 173 ) -> PullRequest { 174 let pr: PullRequest = PullRequest { 175 commit_hash: commit_hash, 176 submitter: self.caller, 177 repo_id: repo_id, 178 sponsor: self.caller, 179 sponsored_at: 0u64, 180 vote_deadline: 0u64, 181 yes_votes: 0u32, 182 no_votes: 0u32, 183 status: 0u8, 184 behavior_flags: 0u8, 185 governance_proposal_id: 0u128, 186 is_shared_repo: is_shared_repo 187 }; 188 189 return pr then finalize(commit_hash, pr, self.caller, submitted_at); 190 } 191 192 finalize submit_pr( 193 pr_hash: field, 194 pr: PullRequest, 195 submitter: address, 196 submitted_at: u64 197 ) { 198 // Check resubmission cooldown 199 let cooldown: ResubmissionCooldown = Mapping::get_or_use( 200 resubmission_cooldowns, 201 pr_hash, 202 ResubmissionCooldown { 203 original_pr_hash: 0field, 204 failed_at: 0u64, 205 cooldown_until: 0u64, 206 submitter: submitter 207 } 208 ); 209 210 // If cooldown exists and hasn't expired, reject submission 211 assert(cooldown.cooldown_until == 0u64 || submitted_at >= cooldown.cooldown_until); 212 213 Mapping::set(pr_registry, pr_hash, pr); 214 215 // Update contributor stats 216 let contributor: Contributor = Mapping::get_or_use( 217 contributors, 218 submitter, 219 Contributor { 220 prs_submitted: 0u32, 221 prs_merged: 0u32, 222 prs_rejected: 0u32, 223 behavior_flags: 0u32, 224 reward_points: 0u64, 225 registered_at: 0u64 226 } 227 ); 228 229 let updated_contributor: Contributor = Contributor { 230 prs_submitted: contributor.prs_submitted + 1u32, 231 prs_merged: contributor.prs_merged, 232 prs_rejected: contributor.prs_rejected, 233 behavior_flags: contributor.behavior_flags, 234 reward_points: contributor.reward_points, 235 registered_at: contributor.registered_at 236 }; 237 238 Mapping::set(contributors, submitter, updated_contributor); 239 } 240 241 // Sponsor a PR (push to vote) - only Code Governors can sponsor 242 transition sponsor_pr( 243 public pr_hash: field, 244 public sponsored_at: u64 245 ) -> field { 246 let vote_deadline: u64 = sponsored_at + VOTE_DURATION; 247 return pr_hash then finalize(pr_hash, self.caller, sponsored_at, vote_deadline); 248 } 249 250 finalize sponsor_pr( 251 pr_hash: field, 252 sponsor: address, 253 sponsored_at: u64, 254 vote_deadline: u64 255 ) { 256 // Verify sponsor is an active Code Governor 257 let gov: CodeGovernor = Mapping::get(code_governors, sponsor); 258 assert_eq(gov.status, 1u8); 259 260 // Verify minimum 50 active voters (decentralization requirement) 261 let total_govs: u32 = Mapping::get(governor_count, 0u8); 262 assert(total_govs >= 50u32); 263 264 // Get current PR 265 let pr: PullRequest = Mapping::get(pr_registry, pr_hash); 266 assert_eq(pr.status, 0u8); 267 268 let updated_pr: PullRequest = PullRequest { 269 commit_hash: pr.commit_hash, 270 submitter: pr.submitter, 271 repo_id: pr.repo_id, 272 sponsor: sponsor, 273 sponsored_at: sponsored_at, 274 vote_deadline: vote_deadline, 275 yes_votes: 0u32, 276 no_votes: 0u32, 277 status: 1u8, 278 behavior_flags: 0u8, 279 governance_proposal_id: 0u128, 280 is_shared_repo: pr.is_shared_repo 281 }; 282 283 Mapping::set(pr_registry, pr_hash, updated_pr); 284 } 285 286 // Cast a vote on a PR 287 transition cast_vote( 288 public pr_hash: field, 289 public vote_type: u8, 290 public flags: u8, 291 public cast_at: u64 292 ) -> Vote { 293 let vote: Vote = Vote { 294 pr_hash: pr_hash, 295 voter: self.caller, 296 vote_type: vote_type, 297 flags: flags, 298 cast_at: cast_at 299 }; 300 301 let vote_key: field = BHP256::hash_to_field(Vote { 302 pr_hash: pr_hash, 303 voter: self.caller, 304 vote_type: 0u8, 305 flags: 0u8, 306 cast_at: 0u64 307 }); 308 309 return vote then finalize(vote_key, vote, pr_hash, vote_type, flags); 310 } 311 312 finalize cast_vote( 313 vote_key: field, 314 vote: Vote, 315 pr_hash: field, 316 vote_type: u8, 317 flags: u8 318 ) { 319 // Verify voter is an active Code Governor 320 let gov: CodeGovernor = Mapping::get(code_governors, vote.voter); 321 assert_eq(gov.status, 1u8); 322 323 // Get current PR 324 let pr: PullRequest = Mapping::get(pr_registry, pr_hash); 325 assert_eq(pr.status, 1u8); 326 327 // Store the vote 328 Mapping::set(votes, vote_key, vote); 329 330 // Update vote counts 331 let new_yes: u32 = pr.yes_votes + (vote_type == 1u8 ? 1u32 : 0u32); 332 let new_no: u32 = pr.no_votes + (vote_type == 0u8 ? 1u32 : 0u32); 333 let new_flags: u8 = pr.behavior_flags | flags; 334 335 let updated_pr: PullRequest = PullRequest { 336 commit_hash: pr.commit_hash, 337 submitter: pr.submitter, 338 repo_id: pr.repo_id, 339 sponsor: pr.sponsor, 340 sponsored_at: pr.sponsored_at, 341 vote_deadline: pr.vote_deadline, 342 yes_votes: new_yes, 343 no_votes: new_no, 344 status: 1u8, 345 behavior_flags: new_flags, 346 governance_proposal_id: pr.governance_proposal_id, 347 is_shared_repo: pr.is_shared_repo 348 }; 349 350 Mapping::set(pr_registry, pr_hash, updated_pr); 351 352 // Update governor's last vote time (resets missed vote counter) 353 let updated_gov: CodeGovernor = CodeGovernor { 354 stake_amount: gov.stake_amount, 355 registered_at: gov.registered_at, 356 missed_votes: 0u8, // Reset on successful vote 357 last_vote_at: vote.cast_at, 358 status: gov.status 359 }; 360 361 Mapping::set(code_governors, vote.voter, updated_gov); 362 } 363 364 // Record a missed vote for a governor (called by system after vote period ends) 365 transition record_missed_vote( 366 public gov_address: address 367 ) -> bool { 368 return true then finalize(gov_address); 369 } 370 371 finalize record_missed_vote(gov_address: address) { 372 let gov: CodeGovernor = Mapping::get(code_governors, gov_address); 373 374 let new_missed: u8 = gov.missed_votes + 1u8; 375 let new_status: u8 = new_missed >= MAX_MISSED_VOTES ? 2u8 : gov.status; 376 377 let updated_gov: CodeGovernor = CodeGovernor { 378 stake_amount: gov.stake_amount, 379 registered_at: gov.registered_at, 380 missed_votes: new_missed, 381 last_vote_at: gov.last_vote_at, 382 status: new_status 383 }; 384 385 Mapping::set(code_governors, gov_address, updated_gov); 386 387 // If deregistered, decrement count 388 if new_status == 2u8 { 389 let current_count: u32 = Mapping::get(governor_count, 0u8); 390 Mapping::set(governor_count, 0u8, current_count - 1u32); 391 } 392 } 393 394 // Finalize voting and determine outcome 395 transition finalize_vote( 396 public pr_hash: field, 397 public finalized_at: u64 398 ) -> u8 { 399 return 0u8 then finalize(pr_hash, finalized_at); 400 } 401 402 finalize finalize_vote( 403 pr_hash: field, 404 finalized_at: u64 405 ) { 406 let pr: PullRequest = Mapping::get(pr_registry, pr_hash); 407 assert_eq(pr.status, 1u8); 408 409 let total_govs: u32 = Mapping::get_or_use(governor_count, 0u8, 1u32); 410 let threshold: u32 = (total_govs * 67u32) / 100u32; 411 412 let passed: bool = pr.yes_votes >= threshold; 413 let new_status: u8 = passed ? 2u8 : 3u8; 414 415 let updated_pr: PullRequest = PullRequest { 416 commit_hash: pr.commit_hash, 417 submitter: pr.submitter, 418 repo_id: pr.repo_id, 419 sponsor: pr.sponsor, 420 sponsored_at: pr.sponsored_at, 421 vote_deadline: pr.vote_deadline, 422 yes_votes: pr.yes_votes, 423 no_votes: pr.no_votes, 424 status: new_status, 425 behavior_flags: pr.behavior_flags, 426 governance_proposal_id: pr.governance_proposal_id, 427 is_shared_repo: pr.is_shared_repo 428 }; 429 430 Mapping::set(pr_registry, pr_hash, updated_pr); 431 432 // If failed, set 48-hour cooldown for resubmission 433 if (!passed) { 434 let cooldown: ResubmissionCooldown = ResubmissionCooldown { 435 original_pr_hash: pr_hash, 436 failed_at: finalized_at, 437 cooldown_until: finalized_at + COOLDOWN_DURATION, 438 submitter: pr.submitter 439 }; 440 Mapping::set(resubmission_cooldowns, pr.commit_hash, cooldown); 441 } 442 443 // Update contributor stats 444 let contributor: Contributor = Mapping::get(contributors, pr.submitter); 445 446 let updated_contributor: Contributor = Contributor { 447 prs_submitted: contributor.prs_submitted, 448 prs_merged: contributor.prs_merged + (passed ? 1u32 : 0u32), 449 prs_rejected: contributor.prs_rejected + (passed ? 0u32 : 1u32), 450 behavior_flags: contributor.behavior_flags + (pr.behavior_flags as u32), 451 reward_points: contributor.reward_points + (passed ? 100u64 : 0u64), 452 registered_at: contributor.registered_at 453 }; 454 455 Mapping::set(contributors, pr.submitter, updated_contributor); 456 457 // For shared repos, initialize cross-chain attestation 458 if (pr.is_shared_repo && passed) { 459 let attestation: CrossChainAttestation = CrossChainAttestation { 460 pr_hash: pr_hash, 461 alpha_passed: false, 462 delta_passed: true, 463 alpha_proposal_id: 0u128, 464 delta_proposal_id: 0u128, 465 finalized_at: 0u64 466 }; 467 Mapping::set(cross_chain_attestations, pr_hash, attestation); 468 } 469 } 470 471 // Create governance proposal for passed PR 472 transition create_governance_proposal( 473 public pr_hash: field, 474 public proposal_id: u128 475 ) -> u128 { 476 return proposal_id then finalize(pr_hash, proposal_id); 477 } 478 479 finalize create_governance_proposal( 480 pr_hash: field, 481 proposal_id: u128 482 ) { 483 let pr: PullRequest = Mapping::get(pr_registry, pr_hash); 484 assert_eq(pr.status, 2u8); // Must be passed 485 486 // For shared repos, check if both chains have passed 487 if (pr.is_shared_repo) { 488 let attestation: CrossChainAttestation = Mapping::get(cross_chain_attestations, pr_hash); 489 assert(attestation.alpha_passed && attestation.delta_passed); 490 } 491 492 // Link proposal to PR 493 let updated_pr: PullRequest = PullRequest { 494 commit_hash: pr.commit_hash, 495 submitter: pr.submitter, 496 repo_id: pr.repo_id, 497 sponsor: pr.sponsor, 498 sponsored_at: pr.sponsored_at, 499 vote_deadline: pr.vote_deadline, 500 yes_votes: pr.yes_votes, 501 no_votes: pr.no_votes, 502 status: 4u8, // proposal_created 503 behavior_flags: pr.behavior_flags, 504 governance_proposal_id: proposal_id, 505 is_shared_repo: pr.is_shared_repo 506 }; 507 508 Mapping::set(pr_registry, pr_hash, updated_pr); 509 Mapping::set(proposal_to_pr, proposal_id, pr_hash); 510 } 511 512 // Receive cross-chain attestation from Alpha 513 transition receive_alpha_attestation( 514 public pr_hash: field, 515 public alpha_passed: bool, 516 public alpha_proposal_id: u128, 517 public finalized_at: u64 518 ) -> bool { 519 return alpha_passed then finalize(pr_hash, alpha_passed, alpha_proposal_id, finalized_at); 520 } 521 522 finalize receive_alpha_attestation( 523 pr_hash: field, 524 alpha_passed: bool, 525 alpha_proposal_id: u128, 526 finalized_at: u64 527 ) { 528 let attestation: CrossChainAttestation = Mapping::get(cross_chain_attestations, pr_hash); 529 530 let updated_attestation: CrossChainAttestation = CrossChainAttestation { 531 pr_hash: pr_hash, 532 alpha_passed: alpha_passed, 533 delta_passed: attestation.delta_passed, 534 alpha_proposal_id: alpha_proposal_id, 535 delta_proposal_id: attestation.delta_proposal_id, 536 finalized_at: finalized_at 537 }; 538 539 Mapping::set(cross_chain_attestations, pr_hash, updated_attestation); 540 } 541 542 // Mark PR as executed after governance proposal passes 543 transition mark_executed( 544 public pr_hash: field, 545 public executed_at: u64 546 ) -> bool { 547 return true then finalize(pr_hash, executed_at); 548 } 549 550 finalize mark_executed( 551 pr_hash: field, 552 executed_at: u64 553 ) { 554 let pr: PullRequest = Mapping::get(pr_registry, pr_hash); 555 assert_eq(pr.status, 4u8); // Must have proposal created 556 557 let updated_pr: PullRequest = PullRequest { 558 commit_hash: pr.commit_hash, 559 submitter: pr.submitter, 560 repo_id: pr.repo_id, 561 sponsor: pr.sponsor, 562 sponsored_at: pr.sponsored_at, 563 vote_deadline: pr.vote_deadline, 564 yes_votes: pr.yes_votes, 565 no_votes: pr.no_votes, 566 status: 5u8, // executed 567 behavior_flags: pr.behavior_flags, 568 governance_proposal_id: pr.governance_proposal_id, 569 is_shared_repo: pr.is_shared_repo 570 }; 571 572 Mapping::set(pr_registry, pr_hash, updated_pr); 573 } 574 575 // Create checkpoint for merged code 576 transition checkpoint_commit( 577 public commit_hash: field, 578 public radicle_oid: field, 579 public finalized_at: u64 580 ) -> Checkpoint { 581 let checkpoint: Checkpoint = Checkpoint { 582 commit_hash: commit_hash, 583 radicle_oid: radicle_oid, 584 approver_count: 1u8, 585 finalized_at: finalized_at 586 }; 587 588 return checkpoint then finalize(commit_hash, checkpoint); 589 } 590 591 finalize checkpoint_commit( 592 commit_hash: field, 593 checkpoint: Checkpoint 594 ) { 595 Mapping::set(checkpoints, commit_hash, checkpoint); 596 } 597 }