Skip to content

Escrow contract improvements — init, deposit, release_milestone, open_dispute#218

Merged
soomtochukwu merged 6 commits into
DXmakers:mainfrom
akargi:feat/issue69
Apr 22, 2026
Merged

Escrow contract improvements — init, deposit, release_milestone, open_dispute#218
soomtochukwu merged 6 commits into
DXmakers:mainfrom
akargi:feat/issue69

Conversation

@akargi
Copy link
Copy Markdown
Contributor

@akargi akargi commented Apr 22, 2026

Closes #69
Branch: feat/issue69

This PR implements a set of improvements to the escrow Soroban contract that harden initialization, token handling, dispute flows, and milestone releases. The goal is safer, more observable, and more debuggable on-chain behavior for the Lance protocol.

Summary of changes

  • Add typed contract errors and events

    • EscrowError (enum) — typed error codes for failure modes (AlreadyInitialized, NotInitialized, Unauthorized, InvalidInput, JobNotFound, InvalidState, AmountMismatch, NoPendingMilestones).
    • EscrowInitializedEvent — emitted when contract is initialized.
    • AgentJudgeUpdatedEvent — emitted when the admin updates the agent judge.
    • DepositEvent — emitted when a client deposits funds for a job.
    • ReleaseMilestoneEvent — emitted when a milestone is released to the freelancer.
    • OpenDisputeEvent — emitted when either party opens a dispute.
  • Initialize/admin improvements

    • initialize(env, admin, agent_judge) -> Result<(), EscrowError>
      • Prevents double initialization; validates input; persists Admin and AgentJudge to instance storage; emits Initialized event.
    • set_agent_judge(env, new_agent_judge) -> Result<(), EscrowError>
      • Admin-only (requires auth), validates input, persists new agent judge, emits AgentJudgeUpdated.
  • Deposit implementation

    • deposit(env, job_id, amount) -> Result<(), EscrowError>
      • Validates job existence and state (Setup only), caller auth, positive amount, presence of milestones, and sum-of-milestones equals the deposit amount.
      • Transfers tokens from client to contract, updates total_amount and state to Funded, emits Deposit event.
  • Milestone release implementation

    • release_milestone(env, job_id, caller) -> Result<(), EscrowError>
      • Caller must be client and job must be in Funded or WorkInProgress.
      • Finds next pending milestone, marks it released, transfers funds to freelancer, updates released_amount and job status, emits ReleaseMilestone event.
  • Open dispute implementation

    • open_dispute(env, job_id, caller) -> Result<(), EscrowError>
      • Caller must be client or freelancer and job must be in Funded or WorkInProgress.
      • Sets job status to Disputed and emits OpenDispute event.
  • Tests

    • Updated unit tests in contracts/escrow/src/lib.rs to use the new Result-based APIs (unwrap on success or assert errors where appropriate).

Why these changes

  • Typed errors make contract failures programmatically discoverable and allow the backend to respond deterministically to different failure modes.
  • Events provide a reliable, off-chain observable trail for state changes. This is critical for backend workers (AI judge, indexing, notifications) to react to on-chain actions.
  • Deposit and release flows now validate critical invariants (milestone sums, authorized callers) to reduce risk of incorrect fund movements.

Security considerations

  • Auth is enforced via require_auth() for caller checks.
  • Token transfers use the soroban token client.
  • Saturating arithmetic is used where safe accumulation is necessary to avoid overflows.

Compatibility notes

  • initialize, deposit, release_milestone, and open_dispute now return Result with typed EscrowError values. Callers must handle those results.
  • Existing backend code or tests that expect panics or specific panic strings should be updated to check for error responses or to adapt to the new events.

How to run tests locally

# From repo root
cargo test -p escrow

Notes on test execution

  • I updated tests to unwrap the new Result returns. I attempted to run tests in the current environment but there was a toolchain sync blocking remote execution. Please run tests locally and paste back any failing output — I'll iterate quickly.

Checklist for acceptance

  • All escrow unit tests pass locally.
  • New event emissions are validated by integration tests (backend watcher / Testnet smoke run).
  • At least one senior engineer has reviewed and approved the changes.
  • Documentation updated in /docs (I can add this in a follow-up).

Next steps I can take

  • Add targeted unit tests for each EscrowError path (JobNotFound, Unauthorized, InvalidState, AmountMismatch, NoPendingMilestones).
  • Update /docs/escrow.md describing the public API and example flows.
  • Open a draft PR on GitHub with this message as the PR body.

Reviewer notes

@akargi akargi requested a review from soomtochukwu as a code owner April 22, 2026 14:30
@drips-wave
Copy link
Copy Markdown

drips-wave Bot commented Apr 22, 2026

@akargi 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

@akargi
Copy link
Copy Markdown
Contributor Author

akargi commented Apr 22, 2026

@soomtochukwu resolved

@soomtochukwu soomtochukwu merged commit a440ca2 into DXmakers:main Apr 22, 2026
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

Development

Successfully merging this pull request may close these issues.

Implement Escrow::open_dispute logic Implement Escrow::release_milestone logic

2 participants