Skip to content

feat(contract): pending milestone count, admin timelock transfer, dis… - #362

Merged
Devdave-0x merged 1 commit into
Devdave-0x:developfrom
kelvin1john0901-blip:feat/contract-milestone-admin-dispute
Jul 29, 2026
Merged

feat(contract): pending milestone count, admin timelock transfer, dis…#362
Devdave-0x merged 1 commit into
Devdave-0x:developfrom
kelvin1john0901-blip:feat/contract-milestone-admin-dispute

Conversation

@kelvin1john0901-blip

Copy link
Copy Markdown

Summary

Implements three platform-health and security features on the Soroban escrow contract.

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Changes

Issue 1 — Pending Milestone Count

Dashboards can now query how many milestones are awaiting approval for a given escrow without fetching and iterating every milestone individually.

  • Added FeatDataKey::PendingMilestoneCount(u64) to persistent storage
  • add_milestone and add_milestone_internal (used by create_milestone) increment the counter when a new MS_PENDING milestone is created
  • approve_milestone decrements the counter when a milestone transitions out of pending
  • reject_milestone decrements the counter when a milestone is rejected
  • New view function: get_pending_milestone_count(escrow_id: u64) -> u32

Issue 2 — Admin Transfer Timelock

Admin key rotation now uses a mandatory ~48-hour timelock between proposal and acceptance, giving time to detect and cancel an unauthorised change before it
takes effect.

  • Added constant ADMIN_TRANSFER_TIMELOCK_LEDGERS = 34_560 (~48 h at 5 s/ledger)
  • propose_admin stores current_ledger + ADMIN_TRANSFER_TIMELOCK_LEDGERS in FeatDataKey::AdminTransferValidAfterLedger
  • accept_admin checks the current ledger against valid_after_ledger and returns EscrowError::E46 if called too early
  • New function cancel_admin_proposal — callable only by the current admin; clears both PendingAdmin and AdminTransferValidAfterLedger
  • New events: AdminProposed (with timelock expiry ledger), AdminAccepted, AdminProposalCancelled

Issue 3 — Dispute Count Tracking

Platform operators can now monitor total disputes filed and per-escrow dispute frequency to assess platform health and arbiter capacity.

  • Added FeatDataKey::TotalDisputeCount (global counter, u32)
  • Added FeatDataKey::DisputeCountByEscrow(u64) (per-escrow counter, u32)
  • raise_dispute increments both counters on every call
  • New view functions: get_total_dispute_count() -> u32, get_dispute_count(escrow_id: u64) -> u32

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Tests

New test modules added:

  • pending_milestone_count_tests — count is 0 for a new escrow; increments on add_milestone/create_milestone; decrements on approve_milestone; decrements on
    reject_milestone
  • admin_timelock_tests — accept_admin before timelock returns E46; accept_admin after timelock succeeds; cancel_admin_proposal clears the proposal; non-admin
    cannot cancel; cancelling when no proposal returns E3
  • dispute_count_tests — total increments on each raise_dispute; per-escrow count is correct; multiple disputes on the same escrow are tracked independently

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Storage impact

All new keys use FeatDataKey (the overflow enum) to avoid adding to the DataKey XDR schema. Persistent storage entries get TTL bumps consistent with the rest
of the codebase. No migration is required — all new counters default to 0 via unwrap_or(0).

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Breaking changes

None. Existing propose_admin / accept_admin callers will see the timelock enforced — accept_admin called immediately after propose_admin will now return E46
instead of succeeding. Existing tests that called accept_admin without advancing the ledger have been updated to advance by ADMIN_TRANSFER_TIMELOCK_LEDGERS +
1.

closes #276
closes #278
closes #279

@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@kelvin1john0901-blip Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Devdave-0x
Devdave-0x merged commit f41061a into Devdave-0x:develop Jul 29, 2026
0 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants