Skip to content

doc: Add low-level design doc for MIMD-0025 - #190

Closed
snawaz wants to merge 20 commits into
mainfrom
snawaz/mimd-0025-design
Closed

doc: Add low-level design doc for MIMD-0025#190
snawaz wants to merge 20 commits into
mainfrom
snawaz/mimd-0025-design

Conversation

@snawaz

@snawaz snawaz commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

⚠️ NOTE: Use notes like this to emphasize something important about the PR.

This could include other PRs this PR is built on top of; API breaking changes; reasons for why the PR is on hold; or anything else you would like to draw attention to.

Status Type ⚠️ Core Change Issue
Ready/Hold Feature/Bug/Tooling/Refactor/Hotfix Yes/No Link

Problem

What problem are you trying to solve?

Solution

How did you solve the problem?

Before & After Screenshots

Insert screenshots of example code output

BEFORE:
[insert screenshot here]

AFTER:
[insert screenshot here]

Other changes (e.g. bug fixes, small refactors)

Deploy Notes

Notes regarding deployment of the contained body of work. These should note any
new dependencies, new scripts, etc.

New scripts:

  • script : script details

New dependencies:

  • dependency : dependency details

Summary by CodeRabbit

  • Documentation
    • Added comprehensive implementation notes for the MIMD-0025 protocol.
    • Documented account structures, lifecycle states, instruction interfaces, validation rules, and end-to-end commitment, challenge, dispute, and payout flows.
    • Clarified verifier selection, staking, timeouts, finalization, dispute resolution, and unresolved design considerations.
    • Added guidance for permissioned bootstrapping, challenge and reveal handling, operator responsibilities, slashing, payout timelocks, and commitment expiration.

snawaz commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The document defines MIMD-0025 bootstrap permissioning, domain-separated hashes, PDA layouts, account schemas, state types, instruction interfaces, payloads, and validation rules. It specifies verifier selection, commitment approval, state buffering, challenges, reveals, dispute resolution, timeouts, staking penalties, payout timelocks, finalization, expiration, and account closure. It also records validator-repository responsibilities and unresolved design parameters.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch snawaz/mimd-0025-design

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mimd-0025-impl.md`:
- Line 287: Update the “FinalizeCommitment” happy-path rule wording to say it
requires the window to be closed, replacing “requires closed window” while
preserving the existing approval requirement.
- Line 207: Update the RaiseChallenge specification and corresponding details at
the referenced challenge-flow section to require Active status, a current slot
strictly before challenge_window_end_slot, and no existing active challenge;
atomically set PendingCommitment.active_challenge during creation so concurrent
challengers cannot create multiple challenges and late challenges cannot block
finalization.
- Around line 208-210: Update the OperatorChallengeResponse rules to require the
submitted account_state_hash and optional state buffer to match
PendingCommitment before opening state. Treat any mismatch as an
operator-invalid outcome and ensure ResolvedOperator cannot finalize that
response; apply the same validation to the corresponding
ChallengerReveal-related rules.
- Around line 139-144: Update StateBuffer and the WriteStateBuffer flow to
retain immutable creation metadata and track covered byte ranges, rejecting
changed metadata, gaps, overlaps, out-of-bounds writes, and writes exceeding
total_len. Require dispute states that need buffer data to supply one, and
permit council resolution or finalization only when the buffer is finalized,
exactly covers total_len, and matches expected_data_hash; apply the same
validation to the referenced paths around the affected state transitions.
- Line 89: Persist a challenge-window extension counter on PendingCommitment,
initialize it when the commitment is created, and update ExtendChallengeWindow
to reject extensions once ProtocolConfig.max_window_extensions is reached.
Increment the counter with checked arithmetic and ensure every relevant
construction, serialization, and extension path carries the new field
consistently.
- Around line 196-200: The commitment flow must preserve configuration values
for in-flight commitments instead of reading updated protocol settings later.
Update the commitment data model and related instructions around
UpdateProtocolConfig so values such as match_penalty_bps, max_window_extensions,
and payout_timelock_slots are snapshotted when the commitment is created, or
bind the commitment to an immutable configuration version; ensure later
matching, expiration, and payout logic uses that frozen data.
- Around line 146-156: Define the missing ChallengeOutcome type with variants
covering invalid reveal, matching state, and challenger timeout outcomes. Update
each terminal branch in the challenge resolution flow, including invalid-reveal,
matching-state, and challenger-timeout handling, to atomically set the terminal
status and outcome, clear PendingCommitment.active_challenge, settle or return
challenger stake as specified, and apply the corresponding finalization
transition.
- Around line 212-213: Update the CouncilVote specification and implementation
to validate member_index bounds, require the signer to match
CouncilCase.member_identities[member_index], confirm the council epoch is
active, reject an already-set vote_bitmap bit, and enforce an open voting
deadline before applying the copied member weight. Apply the same validations to
the corresponding CouncilVote entry referenced later, preserving vote uniqueness
and signer identity guarantees.
- Around line 209-211: Update the state-transition rules for MarkOperatorTimeout
and MarkChallengerRevealTimeout to require the current slot to be at or after
the stored deadline and the commitment/challenge to be in the expected pending
status. Ensure successful operator responses or challenger reveals transition
the state so the corresponding timeout is rejected, making response/reveal and
timeout paths mutually exclusive and preventing premature slashing.
- Around line 83-89: Update ProtocolConfig to define a frozen withdrawal-delay
parameter used consistently by RequestStakeWithdrawal and WithdrawStake. Define
VerifierBond’s locked stake and specify how locked_lamports is increased,
maintained, and released for every outstanding slashable obligation, including
commitments covered by the affected sections. Ensure withdrawal eligibility
preserves sufficient reserved stake until all obligations settle.
- Around line 201-204: The CreateVerifierSetSnapshot flow must define and
enforce the cranker construction authority, validate active verifier bonds,
canonicalize membership ordering, reject duplicate entries, and reject
selected_verifier_count values larger than the resulting snapshot size before
storing it. Ensure the stored verifier_snapshot, including verifier_identity,
verifier_bond, weight, and hash, cannot be modified after creation and is the
authoritative source for later verifier selection and approval.
- Around line 231-234: Update ConsumeCommitmentRandomness to include the stored
VRF request ID alongside randomness and pending commitment. When handling the
message, require the commitment state to be AwaitingRandomness and verify its
stored vrf_request_id matches the supplied request ID before consuming it;
preserve one-time consumption semantics.
- Around line 31-42: Define challenge_window_id in PostCommitment before
computing state_commitment_hash, either by accepting and recording it when the
commitment is created or by deterministically deriving it from shared stored
fields; ensure the identical value is used in both the hash input and
PendingCommitment, and that ConsumeCommitmentRandomness uses that identifier
when starting the challenge window.
- Around line 169-181: Extend CouncilCase with a snapshot of the active council
thresholds needed by ResolveCouncilCase, including the NoQuorum resolution path.
Update ResolveCouncilCase to use the case snapshot, set the pending status/state
source for every resolved outcome, and apply the correct finalization stake
handling for OperatorCorrect, ChallengerCorrect, and NoQuorum.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2d392353-0a38-4bca-a4ca-5542faf791a2

📥 Commits

Reviewing files that changed from the base of the PR and between dcd46dc and 1626195.

📒 Files selected for processing (1)
  • mimd-0025-impl.md

Comment thread mimd-0025-impl.md
Comment thread mimd-0025-impl.md Outdated
Comment on lines +139 to +144
StateBuffer {
role: OperatorFinalize | OperatorChallengeResponse | ChallengerReveal,
authority, account_pubkey, commit_id,
expected_data_hash, total_len, written_len, finalized,
data: Vec<u8>,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Require complete and immutable state-buffer writes.

WriteStateBuffer accepts offset, total len, and expected hash, but StateBuffer has no range or overlap tracking. The rules do not reject gaps, overlaps, changed metadata, out-of-bounds writes, or finalization before exactly total_len bytes are covered. A dispute state can also be supplied without a buffer. Make buffer metadata immutable after creation, enforce exact coverage and size limits, and require a finalized buffer with a matching hash before council resolution or finalization.

Also applies to: 205-206, 245-258

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 139 - 144, Update StateBuffer and the
WriteStateBuffer flow to retain immutable creation metadata and track covered
byte ranges, rejecting changed metadata, gaps, overlaps, out-of-bounds writes,
and writes exceeding total_len. Require dispute states that need buffer data to
supply one, and permit council resolution or finalization only when the buffer
is finalized, exactly covers total_len, and matches expected_data_hash; apply
the same validation to the referenced paths around the affected state
transitions.

Comment thread mimd-0025-impl.md Outdated
Comment thread mimd-0025-impl.md Outdated
Comment on lines +169 to +181
CouncilConfig {
authority, epoch, quorum_bps, supermajority_bps, voting_timeout_slots,
members: Vec<{ identity, weight, active }>,
}

CouncilCase {
challenge, council_epoch, opened_slot, voting_deadline_slot,
operator_votes, challenger_votes, abstain_votes,
vote_bitmap: Vec<u8>,
member_identities: Vec<Pubkey>,
member_weights: Vec<u64>,
outcome: Option<OperatorCorrect | ChallengerCorrect | NoQuorum>,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | sed -n '1,200p'

echo "== target file existence and size =="
wc -l mimd-0025-impl.md 2>/dev/null || true

echo "== relevant line ranges =="
sed -n '140,370p' mimd-0025-impl.md 2>/dev/null || true

echo "== search symbols =="
rg -n "CouncilConfig|CouncilCase|ResolveCouncilCase|NoQuorum|FinalizeCommitment|state_source|quorum_bps|supermajority_bps" mimd-0025-impl.md || true

Repository: magicblock-labs/delegation-program

Length of output: 17106


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== complete 230s around ResolveCouncilCase and FinalizeCommitment =="
sed -n '195,335p' mimd-0025-impl.md

echo "== council symbols in local source =="
rg -n "CouncilConfig|CouncilCase|ResolveCouncilCase|NoQuorum|FinalizeCommitment|state_source|quorum_bps|supermajority_bps|ResolvedOperatorState|ResolvedChallengerState" . --glob '!**/Cargo.lock' --glob '!target/**' || true

Repository: magicblock-labs/delegation-program

Length of output: 8843


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== earlier referenced 70-140 section =="
sed -n '60,135p' mimd-0025-impl.md

echo "== deterministic struct/data mapping probe =="
python3 - <<'PY'
from pathlib import Path
p = Path("mimd-0025-impl.md")
text = p.read_text()
checks = {
    "CouncilConfig_includes_quorums": "CouncilConfig" in text and ("quorum_bps" in text or "supermajority_bps" in text),
    "CouncilCase_outcome_exposes_NoQuorum": "NoQuorum" in text and "outcome: Option<OperatorCorrect | ChallengerCorrect | NoQuorum>" in text,
    "ResolvedOperatorState_exists": "ResolvedOperatorState" in text,
    "ResolvedChallengerState_exists": "ResolvedChallengerState" in text,
}
print(checks)
print("\nNoQuorum state_source:", "NoQuorum" in text and "NoQuorumState" in text)
print("CouncilConfig fields in CouncilCase:", "quorum_bps" in text[text.find("CouncilCase"):text.find("CouncilCase")+500])
PY

Repository: magicblock-labs/delegation-program

Length of output: 3485


Make council resolution paths fully executable.

CouncilCase does not store the active council thresholds, but ResolveCouncilCase still needs them for OperatorCorrect, ChallengerCorrect, and NoQuorum. Add the missing snapshot for NoQuorum, plus the pending status/state source and finalization stake handling for each resolved outcome.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 169 - 181, Extend CouncilCase with a snapshot
of the active council thresholds needed by ResolveCouncilCase, including the
NoQuorum resolution path. Update ResolveCouncilCase to use the case snapshot,
set the pending status/state source for every resolved outcome, and apply the
correct finalization stake handling for OperatorCorrect, ChallengerCorrect, and
NoQuorum.

Comment thread mimd-0025-impl.md Outdated
Comment thread mimd-0025-impl.md Outdated
Comment on lines +208 to +210
| `OperatorChallengeResponse` | opened state metadata | operator signer, pending commitment, challenge, optional state buffer | Opens operator state and starts challenger reveal timeout. |
| `MarkOperatorTimeout` | none | cranker, pending commitment, challenge | Records non-response and waits for challenger reveal. |
| `ChallengerReveal` | opened state metadata, salt | challenger signer, pending commitment, challenge, optional buffer, fee vault, optional council case/config | Validates challenge preimage and either penalizes, dismisses, or opens council case. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Require the operator response to open the committed state.

OperatorChallengeResponse accepts new state metadata, but the rules do not require its account_state_hash to equal PendingCommitment.account_state_hash. ResolvedOperator can then finalize state that was never committed. Require the response and its buffer to match the committed state, or classify a mismatch as operator-invalid and disallow ResolvedOperator.

Also applies to: 245-250

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 208 - 210, Update the
OperatorChallengeResponse rules to require the submitted account_state_hash and
optional state buffer to match PendingCommitment before opening state. Treat any
mismatch as an operator-invalid outcome and ensure ResolvedOperator cannot
finalize that response; apply the same validation to the corresponding
ChallengerReveal-related rules.

Comment thread mimd-0025-impl.md Outdated
Comment thread mimd-0025-impl.md Outdated
Comment thread mimd-0025-impl.md Outdated
Comment thread mimd-0025-impl.md
- `ChallengerReveal` has four terminal branches:
invalid hash, matching state, mismatch after operator response, valid reveal
after operator timeout.
- `FinalizeCommitment` on the happy path requires closed window, approval

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use one modal in the finalization rule.

Change “requires closed window” to “requires the window to be closed.”

🧰 Tools
🪛 LanguageTool

[style] ~287-~287: The double modal “requires closed” is nonstandard (only accepted in certain dialects). Consider “to be closed”.
Context: ...eCommitment` on the happy path requires closed window, approval threshold, no unreso...

(NEEDS_FIXED)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` at line 287, Update the “FinalizeCommitment” happy-path
rule wording to say it requires the window to be closed, replacing “requires
closed window” while preserving the existing approval requirement.

Source: Linters/SAST tools

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mimd-0025-impl.md (1)

58-98: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Freeze canonical hash inputs.

Domain separation does not define the bytes that are hashed. Specify the hash algorithm, exact domain-tag bytes, field order, integer and enum encoding, option and vector encoding, and DA pointer encoding. Require operators, verifiers, challengers, and resolvers to use the same preimage format.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 58 - 98, Update the Hashes section to freeze
the canonical preimage format: specify the hash algorithm, exact domain-tag
bytes, field order, integer and enum encodings, option/vector representations,
and DA pointer encoding for every hash. State that operators, verifiers,
challengers, and resolvers must use this identical serialization, and remove
these items from the open parameters list while leaving unrelated parameters
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mimd-0025-impl.md`:
- Line 127: Define a fixed maximum for VerifierSetSnapshot.entries, including a
serialized-size bound, and enforce both limits before storing any snapshot.
Reject snapshots exceeding either limit while preserving the existing valid
snapshot flow.
- Around line 387-388: Define how dispute resolution obtains and immutably binds
the DA record, replay range, base-state identity, and deterministic
runtime/configuration to the commitment. Specify the exact DA-unavailable
outcome, including resulting state, stake handling, and payout transition,
instead of leaving it to the resolver policy.
- Line 389: Update the payout specification around PayoutTimelock and
ClaimPayout to define the funding account, slash and challenger payout amounts,
beneficiary derivation, and atomic settlement conditions. Require ClaimPayout to
verify current_slot >= unlock_slot and claimed == false before transferring
funds, then mark the timelock claimed as part of the same atomic operation.
- Around line 127-128: Validate approval configuration during both
initialization and updates: require selected_verifier_count to be greater than
zero and approval_threshold to be positive and no greater than
selected_verifier_count. Reject invalid configurations before they are stored or
used, while preserving valid configuration behavior.
- Around line 37-43: Update the RegisterOperator and RegisterVerifier
instruction flows to enforce permissioned-mode admission through a configured
signer, allowlist, or on-chain admission state, including validating the
authority before registration succeeds. Alternatively, revise the documented
bootstrap behavior so these registrations are explicitly permissionless and
remove the conflicting permissioned-mode claim.
- Line 106: Update the PDA account specifications in the ProtocolConfig table
and every other PDA definition to explicitly fix seed order, byte encoding for
Pubkey, u64, enum values, and role tags, plus maximum seed lengths. Ensure each
PDA has a complete deterministic derivation schema that clients can implement
consistently.

---

Outside diff comments:
In `@mimd-0025-impl.md`:
- Around line 58-98: Update the Hashes section to freeze the canonical preimage
format: specify the hash algorithm, exact domain-tag bytes, field order, integer
and enum encodings, option/vector representations, and DA pointer encoding for
every hash. State that operators, verifiers, challengers, and resolvers must use
this identical serialization, and remove these items from the open parameters
list while leaving unrelated parameters unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8ef23319-7dad-4cdf-8c6e-8969d437a102

📥 Commits

Reviewing files that changed from the base of the PR and between 1626195 and ba61040.

📒 Files selected for processing (1)
  • mimd-0025-impl.md

Comment thread mimd-0025-impl.md Outdated
Comment thread mimd-0025-impl.md Outdated
Comment thread mimd-0025-impl.md Outdated
operator_response_timeout_slots,
challenger_reveal_timeout_slots,
payout_timelock_slots,
selected_verifier_count, approval_threshold, max_window_extensions,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

Set a hard verifier snapshot limit.

VerifierSetSnapshot.entries is described as bounded, but no maximum entry count or serialized-size limit is defined. Add and enforce a fixed limit before storing a snapshot. This prevents oversized accounts and transactions from exceeding runtime limits.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` at line 127, Define a fixed maximum for
VerifierSetSnapshot.entries, including a serialized-size bound, and enforce both
limits before storing any snapshot. Reject snapshots exceeding either limit
while preserving the existing valid snapshot flow.

Comment thread mimd-0025-impl.md Outdated
Comment on lines +127 to +128
selected_verifier_count, approval_threshold, max_window_extensions,
match_penalty_bps,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject impossible approval configurations.

Validate selected_verifier_count > 0 and 0 < approval_threshold <= selected_verifier_count during configuration initialization and updates. A zero threshold permits finalization without approvals. A threshold above the selected count makes happy-path finalization impossible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 127 - 128, Validate approval configuration
during both initialization and updates: require selected_verifier_count to be
greater than zero and approval_threshold to be positive and no greater than
selected_verifier_count. Reject invalid configurations before they are stored or
used, while preserving valid configuration behavior.

Comment thread mimd-0025-impl.md
Comment thread mimd-0025-impl.md
- Bounded vector vs Merkleized verifier snapshots.
- Resolver no-decision policy.
- DA-unavailable or replay-insufficient policy.
- Operator slash amount and challenger payout amount.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Define payout funding and settlement.

PayoutTimelock and ClaimPayout are part of the interface, but the slash amount and challenger payout remain unspecified. Define the funding account, amount, beneficiary derivation, and atomic claim conditions. ClaimPayout must require current_slot >= unlock_slot and claimed == false before transferring funds and marking the timelock claimed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` at line 389, Update the payout specification around
PayoutTimelock and ClaimPayout to define the funding account, slash and
challenger payout amounts, beneficiary derivation, and atomic settlement
conditions. Require ClaimPayout to verify current_slot >= unlock_slot and
claimed == false before transferring funds, then mark the timelock claimed as
part of the same atomic operation.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mimd-0025-impl.md (1)

72-83: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Define canonical encoding for the state commitment hash.

state_commitment_hash now includes verifier_registry and verifier_registry_hash, but their types and byte representations are not defined. Specify whether verifier_registry is the PDA key, the full entry set, or an immutable snapshot identifier. Define field order, fixed-width encodings, option tags, and length delimiters before implementation. Otherwise, different implementations can produce different commitment hashes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 72 - 83, Define the canonical byte encoding
for every input to state_commitment_hash, especially verifier_registry and
verifier_registry_hash: specify whether verifier_registry is a PDA key, full
entry set, or immutable snapshot identifier, then document field order,
fixed-width representations, option tags, and length delimiters. Ensure all
implementations hash the identical canonical serialization before proceeding
with implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mimd-0025-impl.md`:
- Line 257: Validate selected_verifier_index in the approval-update logic before
accessing selected_verifiers or approval_bitmap: ensure it is in range, the
signer matches the verifier at that index, and the corresponding bitmap bit
exists and is unset before setting it. Reject malformed input rather than
performing any update, covering the same checks in the logic around the
referenced approval-update lines.

---

Outside diff comments:
In `@mimd-0025-impl.md`:
- Around line 72-83: Define the canonical byte encoding for every input to
state_commitment_hash, especially verifier_registry and verifier_registry_hash:
specify whether verifier_registry is a PDA key, full entry set, or immutable
snapshot identifier, then document field order, fixed-width representations,
option tags, and length delimiters. Ensure all implementations hash the
identical canonical serialization before proceeding with implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b606e709-b1fd-4e86-810c-8b809ea262ec

📥 Commits

Reviewing files that changed from the base of the PR and between ba61040 and 83b4550.

📒 Files selected for processing (1)
  • mimd-0025-impl.md

Comment thread mimd-0025-impl.md Outdated
}

ApproveCommitment {
selected_verifier_index: u32,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate selected_verifier_index before updating approvals.

Require the index to be within selected_verifiers, require the signer to equal the entry at that index, and verify that the corresponding approval_bitmap bit exists and is unset before setting it. Otherwise, malformed input can cause an out-of-bounds access or record approval against the wrong slot.

Also applies to: 300-303

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` at line 257, Validate selected_verifier_index in the
approval-update logic before accessing selected_verifiers or approval_bitmap:
ensure it is in range, the signer matches the verifier at that index, and the
corresponding bitmap bit exists and is unset before setting it. Reject malformed
input rather than performing any update, covering the same checks in the logic
around the referenced approval-update lines.

@snawaz
snawaz force-pushed the snawaz/mimd-0025-design branch from 4d825ab to 753a36a Compare August 3, 2026 18:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mimd-0025-impl.md (1)

60-99: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Specify the hash serialization before implementation.

challenge_hash is an on-chain commitment whose preimage ChallengerReveal must validate, but the spec leaves the hash algorithm and byte-level encoding open. Define the field order, integer/enum encoding, length prefixes, and hash algorithm for the domain tags used by account_state_hash, da_pointer_hash, state_commitment_hash, and challenge_hash. Otherwise, honest operators, challengers, and resolvers can compute incompatible hashes from the same commitment/reveal data.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 60 - 99, Specify a canonical serialization
for all hash preimages in the Hashes section before implementation: define the
hash algorithm, exact field order, domain-tag encoding, integer and enum
representations, byte/string length prefixes, and DA pointer encoding for
account_state_hash, da_pointer_hash, state_commitment_hash, and challenge_hash.
Ensure ChallengerReveal validation uses this same encoding so all participants
derive identical commitments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mimd-0025-impl.md`:
- Around line 154-155: Define the withdrawal unlock rule for OperatorBond and
VerifierBond by adding a ProtocolConfig withdrawal delay or immutable
withdraw_available_slot, then update WithdrawStake to require current_slot to
reach the configured unlock value, the bond to be exiting, and no stake to
remain locked before allowing withdrawal.
- Line 144: Update PendingCommitment to store an immutable maximum extension
limit and an extensions_used counter initialized from
ProtocolConfig.max_window_extensions; update ExtendChallengeWindow to atomically
reject requests once the limit is reached and increment extensions_used only
after a successful extension, without treating challenge_window_id as the count.
- Around line 134-136: Enforce the configured minimum amounts from the
min_operator_bond, min_verifier_bond, and min_challenger_stake fields at every
corresponding registration and challenge instruction, including the referenced
sections. Reject underfunded or zero-stake inputs before state changes, and
ensure the validated amount is transferred or locked atomically with
registration or challenge creation.

---

Outside diff comments:
In `@mimd-0025-impl.md`:
- Around line 60-99: Specify a canonical serialization for all hash preimages in
the Hashes section before implementation: define the hash algorithm, exact field
order, domain-tag encoding, integer and enum representations, byte/string length
prefixes, and DA pointer encoding for account_state_hash, da_pointer_hash,
state_commitment_hash, and challenge_hash. Ensure ChallengerReveal validation
uses this same encoding so all participants derive identical commitments.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6e82dba5-a903-4f06-a7f4-50c2a4e3b69b

📥 Commits

Reviewing files that changed from the base of the PR and between 83b4550 and 753a36a.

📒 Files selected for processing (1)
  • mimd-0025-impl.md

Comment thread mimd-0025-impl.md
Comment on lines +134 to +136
pub min_operator_bond: u64,
pub min_verifier_bond: u64,
pub min_challenger_stake: u64,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Enforce the configured minimum stake amounts.

The configuration defines minimum operator, verifier, and challenger stakes. The instruction contracts do not state lower-bound checks for the supplied amounts. An underfunded registration or zero-stake challenge can bypass economic protections or block finalization at low cost.

Require each amount to meet its configured minimum. Transfer or lock the amount atomically with registration or challenge creation.

Also applies to: 315-316, 326-326, 363-366

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 134 - 136, Enforce the configured minimum
amounts from the min_operator_bond, min_verifier_bond, and min_challenger_stake
fields at every corresponding registration and challenge instruction, including
the referenced sections. Reject underfunded or zero-stake inputs before state
changes, and ensure the validated amount is transferred or locked atomically
with registration or challenge creation.

Comment thread mimd-0025-impl.md
Comment thread mimd-0025-impl.md
Comment on lines +154 to +155
pub withdraw_requested_slot: Option<u64>,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Define the withdrawal unlock condition.

OperatorBond and VerifierBond store withdraw_requested_slot, but ProtocolConfig defines no withdrawal delay or unlock slot. WithdrawStake also has no stated current-slot check. This leaves the stake-unlock rule implementation-dependent.

Add a withdrawal delay or store an immutable withdraw_available_slot. Require current_slot to reach that value, the bond to be exiting, and no stake to remain locked before withdrawal.

Also applies to: 162-163, 317-318

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 154 - 155, Define the withdrawal unlock rule
for OperatorBond and VerifierBond by adding a ProtocolConfig withdrawal delay or
immutable withdraw_available_slot, then update WithdrawStake to require
current_slot to reach the configured unlock value, the bond to be exiting, and
no stake to remain locked before allowing withdrawal.

@snawaz
snawaz force-pushed the snawaz/mimd-0025-design branch from 73c9739 to 649a41d Compare August 3, 2026 19:21
@snawaz
snawaz force-pushed the snawaz/mimd-0025-design branch from a1f35b6 to a313bb1 Compare August 3, 2026 19:32
@snawaz
snawaz force-pushed the snawaz/mimd-0025-design branch from a313bb1 to 2fa8b2a Compare August 3, 2026 19:35

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mimd-0025-impl.md`:
- Around line 341-346: Align the opened-state flow across
OperatorChallengeResponseData and ChallengerRevealData with FinalizeCommitment:
either reject None state_buffer values before marking the state resolved, or
introduce an explicit opened-state account and bind it through
FinalizeCommitmentStateSource. Ensure every resolved opened state supplies the
state buffer/account required by FinalizeCommitment.
- Line 334: Update PostCommitment and PostCommitmentData handling to bind the
instruction to the canonical CommitRecord: include the existing record account
and validate that its identity, target account, sequential nonce, and committed
lamports match the supplied commitment data. Ensure downstream consumers use the
validated CommitRecord values, or explicitly document and implement this path as
the replacement canonical source.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b6f4abef-52a2-417a-8f0c-67df125eb1b8

📥 Commits

Reviewing files that changed from the base of the PR and between 753a36a and 11dbc64.

📒 Files selected for processing (1)
  • mimd-0025-impl.md

Comment thread mimd-0025-impl.md Outdated
| --- | --- | --- |
| `RequestStakeWithdrawal`<ul><li>ix-data: <code>actor_kind</code></li><li>accounts: <strong>actor signer, bond, config</strong></li></ul> | Operator or verifier | Marks bonded stake as exiting. The stake cannot be withdrawn until the configured delay passes and no locks remain. |
| `WithdrawStake`<ul><li>ix-data: <code>actor_kind</code></li><li>accounts: <strong>actor signer, bond, config</strong></li></ul> | Operator or verifier | Withdraws unlocked stake after the exit delay. Slashed or locked stake stays in the protocol. |
| `PostCommitment`<ul><li>ix-data: <code>commitment</code></li><li>accounts: <strong>operator, operator bond, pending commitment, delegated account, delegation record, config, verifier registry, DLP identity PDA, VRF queue/program</strong></li></ul> | Operator | Creates an `AwaitingRandomness` commitment, stores the current `registry_revision`, locks any commitment-local stake if needed, and requests VRF. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C 5 'PostCommitment|commit_record|commit_id|nonce|lamports' \
  mimd-0025-impl.md \
  dlp-api/src/state/commit_record.rs \
  src/processor/fast/commit_state.rs \
  src/processor/fast/commit_finalize.rs

Repository: magicblock-labs/delegation-program

Length of output: 28775


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file list =="
git ls-files | rg '(^|/)(mimd-0025-impl\.md|commit_record\.rs|commit_state\.rs|commit_finalize\.rs|.*mimd.*\.rs|.*MIMD.*\.rs)$' || true

echo
echo "== PostCommitment references =="
rg -n 'PostCommitment|post_commitment|pending commitment|CommitRecord|state_commitment_hash|last_commit_id|commit_id|lamports' mimd-0025-impl.md src dlp-api -g '!target' -g '!**/*.lock' || true

echo
echo "== relevant mimd sections =="
sed -n '180,230p' mimd-0025-impl.md
sed -n '328,368p' mimd-0025-impl.md
sed -n '423,432p' mimd-0025-impl.md

Repository: magicblock-labs/delegation-program

Length of output: 36098


Bind PostCommitment to the canonical commit record.

PostCommitmentData supplies commit_id and lamports directly, but PostCommitment does not include the existing CommitRecord nor enforce equality with it. The canonical DLP path stores identity, target account, sequential nonce, and committed lamports in CommitRecord; include and check that record here, or document why this path replaces that canonical source and ensure downstream consumers use the source actually written.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` at line 334, Update PostCommitment and PostCommitmentData
handling to bind the instruction to the canonical CommitRecord: include the
existing record account and validate that its identity, target account,
sequential nonce, and committed lamports match the supplied commitment data.
Ensure downstream consumers use the validated CommitRecord values, or explicitly
document and implement this path as the replacement canonical source.

Comment thread mimd-0025-impl.md Outdated
Comment on lines +341 to +346
| `OperatorChallengeResponse`<ul><li>ix-data: <code>state</code></li><li>accounts: <strong>operator signer, pending commitment, challenge, optional state buffer</strong></li></ul> | Operator | Opens the operator's claimed state for the challenged commitment and starts the challenger reveal timeout. |
| `MarkOperatorTimeout`<ul><li>ix-data: <code>empty</code></li><li>accounts: <strong>cranker, pending commitment, challenge</strong></li></ul> | Cranker | Records that the operator missed the response deadline. The challenger must still reveal the challenge preimage. |
| `ChallengerReveal`<ul><li>ix-data: <code>state, salt</code></li><li>accounts: <strong>challenger signer, pending commitment, challenge, optional buffer, fee vault</strong></li></ul> | Challenger | Verifies the challenge preimage and opened state. It slashes invalid reveals, penalizes matching reveals, or moves mismatches to resolver decision. |
| `MarkChallengerRevealTimeout`<ul><li>ix-data: <code>empty</code></li><li>accounts: <strong>cranker, pending commitment, challenge, fee vault</strong></li></ul> | Cranker | Slashes challenger stake when the reveal deadline passes without a valid reveal. |
| `ResolveDispute`<ul><li>ix-data: <code>decision</code></li><li>accounts: <strong>resolver signer, challenge, pending commitment, operator bond, fee vault, optional payout timelock</strong></li></ul> | Resolver multisig | Applies the multisig decision for a valid mismatch: operator correct or challenger correct. |
| `FinalizeCommitment`<ul><li>ix-data: <code>state_source</code></li><li>accounts: <strong>finalizer, pending commitment, delegated account, delegation record/metadata, state buffer, optional challenge, config</strong></li></ul> | Finalizer or cranker | Applies the final state after the happy path or after dispute resolution. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C 5 'OperatorChallengeResponse|ChallengerReveal|state_buffer|OpenedState|FinalizeCommitment' \
  mimd-0025-impl.md

Repository: magicblock-labs/delegation-program

Length of output: 8596


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== File outline =="
ast-grep outline mimd-0025-impl.md --match 'Instruction Data|Instruction Rules|Failure Scenarios' --view expanded || true

echo
echo "== Relevant specs around instruction data and finalize state source =="
sed -n '320,445p' mimd-0025-impl.md | cat -n

echo
echo "== Search for FinalizeCommitmentStateSource variants =="
rg -n -C 4 'FinalizeCommitmentStateSource|PendingOperatorState|ResolvedOperatorState|ResolvedChallengerState|WriteStateBuffer|FinalizeStateBuffer|state_buffer' mimd-0025-impl.md

Repository: magicblock-labs/delegation-program

Length of output: 15378


Make every resolved opened state finalizable.

OperatorChallengeResponseData and ChallengerRevealData allow state_buffer to be None, while FinalizeCommitment requires a state buffer with no alternate opened-state account. Reject missing buffers, or define an explicit opened-state account and bind it through FinalizeCommitmentStateSource.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 341 - 346, Align the opened-state flow across
OperatorChallengeResponseData and ChallengerRevealData with FinalizeCommitment:
either reject None state_buffer values before marking the state resolved, or
introduce an explicit opened-state account and bind it through
FinalizeCommitmentStateSource. Ensure every resolved opened state supplies the
state buffer/account required by FinalizeCommitment.

@snawaz
snawaz force-pushed the snawaz/mimd-0025-design branch 2 times, most recently from 925cdc2 to bc4ff5e Compare August 4, 2026 08:31
@snawaz
snawaz force-pushed the snawaz/mimd-0025-design branch from bc4ff5e to 7fda1f5 Compare August 4, 2026 08:34
@snawaz
snawaz force-pushed the snawaz/mimd-0025-design branch from fa86000 to 1209c5c Compare August 4, 2026 22:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants