/ programs / forge_delta / src / main.adl
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  }