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