You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
reclaim_expired_escrow is permissionless and refunds an expired Locked escrow
to the sender. It makes zero cross-contract calls — the delivery record is
never informed:
The corresponding DeliveryRecord retains whatever status it held — Pending, Active, or InTransit — indefinitely.
Why It Matters
The protocol ends up in a state its own consistency check classifies as invalid. validate_state_sync maps Cancelled → Refunded as the only synchronized pairing
involving a refund, so a reclaimed escrow leaves combinations like (Active, Refunded) that get_combined_state reports as desynchronized —
correctly, but with no mechanism to resolve it.
The delivery is also functionally stuck. Its escrow is gone, so confirm_delivery
would fail at mark_holdback_escrow, and cancel_delivery would fail at refund_escrow because the escrow is no longer Locked (and see issue #295 for
the missing-escrow case). A driver may still be assigned and believe the job is
live.
Because reclaim_expired_escrow is callable by anyone, this state can be induced
by any third party once the 30-day expiry has passed, without the sender's or
driver's involvement.
Proposed Solution
Have the reclaim path transition the delivery to Cancelled, restoring the
synchronized pairing the state machine already defines for a refund.
That requires the escrow contract to hold the delivery contract's address and
cross-call it, which it does not do today — the same wiring issue #294 proposes.
An alternative is a delivery-side reclaim entry point that drives both
contracts in the correct order, keeping the cross-contract direction consistent
with the existing delivery → escrow flow.
Whichever direction is chosen, validate_transition must permit the resulting
delivery transition: InTransit → Cancelled is not currently legal and would need
to be added deliberately, or the reclaim restricted to deliveries in states from
which cancellation is already valid.
Acceptance Criteria
Reclaiming an expired escrow leaves delivery and escrow states synchronized
get_combined_state reports synchronized after a reclaim
The permitted delivery transitions are decided explicitly and reflected in validate_transition
Reclaim remains permissionless
The expiry precondition and Locked-only guard are unchanged
Regression test asserts post-reclaim synchronization from each reachable delivery status
Technical Notes
validate_transition currently allows Pending → Cancelled and Active → Cancelled but notInTransit → Cancelled; a reclaim of an in-transit delivery therefore has no legal target state today.
EscrowRecord.expires_at is set to created_at + 30 days at creation and is only consulted by this function.
The cross-contract direction matters: every existing call runs delivery → escrow, so adding escrow → delivery introduces a new dependency edge — weigh that against a delivery-side entry point.
Problem Statement
reclaim_expired_escrowis permissionless and refunds an expiredLockedescrowto the sender. It makes zero cross-contract calls — the delivery record is
never informed:
The corresponding
DeliveryRecordretains whatever status it held —Pending,Active, orInTransit— indefinitely.Why It Matters
The protocol ends up in a state its own consistency check classifies as invalid.
validate_state_syncmapsCancelled → Refundedas the only synchronized pairinginvolving a refund, so a reclaimed escrow leaves combinations like
(Active, Refunded)thatget_combined_statereports as desynchronized —correctly, but with no mechanism to resolve it.
The delivery is also functionally stuck. Its escrow is gone, so
confirm_deliverywould fail at
mark_holdback_escrow, andcancel_deliverywould fail atrefund_escrowbecause the escrow is no longerLocked(and see issue #295 forthe missing-escrow case). A driver may still be assigned and believe the job is
live.
Because
reclaim_expired_escrowis callable by anyone, this state can be inducedby any third party once the 30-day expiry has passed, without the sender's or
driver's involvement.
Proposed Solution
Have the reclaim path transition the delivery to
Cancelled, restoring thesynchronized pairing the state machine already defines for a refund.
That requires the escrow contract to hold the delivery contract's address and
cross-call it, which it does not do today — the same wiring issue #294 proposes.
An alternative is a delivery-side
reclaimentry point that drives bothcontracts in the correct order, keeping the cross-contract direction consistent
with the existing
delivery → escrowflow.Whichever direction is chosen,
validate_transitionmust permit the resultingdelivery transition:
InTransit → Cancelledis not currently legal and would needto be added deliberately, or the reclaim restricted to deliveries in states from
which cancellation is already valid.
Acceptance Criteria
get_combined_statereports synchronized after a reclaimvalidate_transitionLocked-only guard are unchangedTechnical Notes
validate_transitioncurrently allowsPending → CancelledandActive → Cancelledbut notInTransit → Cancelled; a reclaim of an in-transit delivery therefore has no legal target state today.EscrowRecord.expires_atis set tocreated_at + 30 daysat creation and is only consulted by this function.validate_state_syncreports every confirmed delivery as desynchronized because it has noHoldbackcase #198 coversvalidate_state_sync's missingHoldbackcase; this issue concerns a different unsynchronized pairing.Relevant Files
contracts/escrow_contract/lib.rs—reclaim_expired_escrowcontracts/delivery_contract/lib.rs—validate_transition,cancel_delivery,validate_state_synccontracts/escrow_contract/test.rs—test_reclaim_expired_escrow_refunds_senderTesting Requirements
TotalLockeddecrement unchangedLockedescrowsInTransitdelivery, given the transition gapDefinition of Done
Complexity
Medium
Estimated Effort
4–8 hours
Dependencies
Shares the escrow → delivery wiring question with #294; the two should agree on direction.