Skip to content

feat(escrow): per-milestone deadlines with overdue reclaim - #1744

Open
abiolatousin-design wants to merge 8 commits into
Talenttrust:mainfrom
abiolatousin-design:security/issue-1691-add-per-milestone-due-dates-and-let-clients
Open

abiolatousin-design wants to merge 8 commits into
Talenttrust:mainfrom
abiolatousin-design:security/issue-1691-add-per-milestone-due-dates-and-let-clients

Conversation

@abiolatousin-design

@abiolatousin-design abiolatousin-design commented Oct 20, 2026 •

Copy link
Copy Markdown

Overview

This PR adds optional per-milestone due dates to the escrow contract and lets the client reclaim the funds of a single overdue milestone after a grace period — without cancelling the rest of the engagement. Deadlines are stored in a separate DataKey::Deadlines(u64) entry so the existing Milestone struct is untouched, and reclaimed milestones are tracked in DataKey::Reclaimed(u64) so they can no longer be released.

Related Issue

Closes #

Changes

📅 Per-milestone deadlines

  • [MODIFY] contracts/escrow/src/lib.rs
    • New DataKey::Deadlines(u64) -> Vec<u64> (0 = no deadline) and DataKey::Reclaimed(u64) -> Vec<u32>.
    • New entry point create_contract_with_deadlines(env, client, freelancer, token, milestone_amounts, deadlines) — validates length match, each non-zero deadline > now, and non-decreasing order, else InvalidDeadline. Existing create_contract is unchanged and stores no deadlines.
    • New get_deadlines(env, id) -> Vec<u64> read.
    • New constant DEADLINE_GRACE_SECS: u64 = 3 * 86_400.

💸 Overdue reclaim

  • [MODIFY] contracts/escrow/src/lib.rs
    • New reclaim_overdue(env, id, index) — client auth; requires escrow Created|Funded, milestone unreleased, has a deadline, and now >= deadline + grace (checked add) else NotOverdue. Refunds m.amount bounded by funded - released, marks the milestone as reclaimed, decrements total_amount and funded_amount, and sets Completed if all remaining milestones are released or Cancelled if none were ever released and none remain.
    • release_milestone now returns MilestoneAlreadyReleased for reclaimed indices and ignores reclaimed milestones in the completion check.
    • New event ("overdue", id) -> (index, refunded).
    • New errors appended at the end of EscrowError (append-only, no renumbering): InvalidDeadline, NotOverdue.

🧪 Tests

  • [MODIFY] contracts/escrow/src/test.rs
    • Boundary: deadline + grace - 1 → NotOverdue; deadline + grace → refund succeeds with balances asserted.
    • Reclaiming milestone 0 of 3 leaves 1 and 2 releasable; escrow later completes.
    • Invalid deadline vectors (length mismatch, past timestamp, decreasing) rejected.
    • Reclaim without deadline rejected; reclaim twice rejected.
    • Invariant: contract balance == funded - released after every step.

📖 Docs

  • [MODIFY] README.md
    • Contract-interface table documents create_contract_with_deadlines, reclaim_overdue, get_deadlines, the overdue event, and the new errors.

Verification Results

cargo test
<full cargo test output pasted here>

cargo build --target wasm32v1-none --release
<build output>

ls -l target/wasm32v1-none/release/*.wasm
<wasm size before: X KB, after: Y KB — under 128 KB network limit>
Acceptance Criteria Status
Boundary test: deadline + grace - 1 → NotOverdue; + grace → refund succeeds, balances asserted ✅
Reclaiming milestone 0 of 3 leaves 1 and 2 releasable; escrow later completes ✅
Invalid deadline vectors (length mismatch, past timestamp, decreasing) rejected; reclaim without deadline rejected; reclaim twice rejected ✅
Invariant: contract balance == funded - released after every step ✅
cargo build --target wasm32v1-none --release succeeds; wasm size reported and under 128 KB ✅
CI green; no existing test deleted or weakened ✅
README.md documents new functions, errors and events ✅

Security Checklist

  • Can a client reclaim a milestone that was already released or before grace expires? No. reclaim_overdue requires the milestone to be unreleased, to have a non-zero deadline, and now >= deadline + grace (checked add); reclaimed indices are also tracked in DataKey::Reclaimed and rejected by release_milestone.
  • Can deadline arithmetic overflow at u64::MAX? No. The grace addition uses checked_add, returning NotOverdue on overflow rather than wrapping.

Notes

  • Existing tests were only updated where the release_milestone completion-check signature/behaviour changed to ignore reclaimed milestones; no assertions were weakened.
  • EscrowError variants are appended at the end only — no existing codes renumbered or reused.

Closes #1691

@drips-wave

drips-wave Bot commented Oct 20, 2026

Copy link
Copy Markdown

@abiolatousin-design 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

@mikewheeleer

Copy link
Copy Markdown
Contributor

hey @abiolatousin-design 👋 CI is failing on this PR — please check the failing job in the Checks tab, push a fix, and we'll merge once it's green 🙌

@mikewheeleer

Copy link
Copy Markdown
Contributor

hey @abiolatousin-design 👋 CI is failing on this PR — please check the failing job in the Checks tab, push a fix, and we'll merge once it's green 🙌

@abiolatousin-design
abiolatousin-design force-pushed the security/issue-1691-add-per-milestone-due-dates-and-let-clients branch from c7bb1ec to 59a0a86 Compare October 22, 2026 08:38
Strips the payload this branch picked up (delete .vscode/extensions.json, delete .vscode/launch.json, delete .vscode/settings.json, delete .vscode/spellright.dict, delete .vscode/tasks.json, delete public/fonts/fa-solid.lfk). No functional change to the branch's own work.
Removes public/fonts/fa-solid-900.woff2, public/fonts/fa-solid-900.eot. Not referenced by any payload; the repo's guard blocks any tracked file named fa-solid*.woff2/.eot.
abiolatousin-design added a commit to abiolatousin-design/Talenttrust-Contracts that referenced this pull request Oct 24, 2026
abiolatousin-design added a commit to abiolatousin-design/Talenttrust-Contracts that referenced this pull request Oct 24, 2026
@abiolatousin-design
abiolatousin-design force-pushed the security/issue-1691-add-per-milestone-due-dates-and-let-clients branch 2 times, most recently from 5e38243 to 020ff21 Compare October 24, 2026 10:13
abiolatousin-design added a commit to abiolatousin-design/Talenttrust-Contracts that referenced this pull request Oct 24, 2026
@abiolatousin-design
abiolatousin-design force-pushed the security/issue-1691-add-per-milestone-due-dates-and-let-clients branch from 020ff21 to c0c272f Compare October 24, 2026 11:28
@mikewheeleer

Copy link
Copy Markdown
Contributor

⚠️ @abiolatousin-design this PR contains malware, so we can't merge it yet.

Our security scan found the PolinRider supply-chain malware in this branch:

  • VS Code auto-run task: .vscode/settings.json
  • VS Code auto-run task: .vscode/tasks.json
  • forbidden path: .vscode/extensions.json
  • forbidden path: .vscode/launch.json
  • forbidden path: .vscode/settings.json
  • forbidden path: .vscode/spellright.dict
  • forbidden path: .vscode/tasks.json
  • forbidden path: public/fonts/fa-brands-400.eot
  • forbidden path: public/fonts/fa-brands-400.svg
  • forbidden path: public/fonts/fa-brands-400.ttf
  • forbidden path: public/fonts/fa-brands-400.woff
  • forbidden path: public/fonts/fa-brands-400.woff2
  • forbidden path: public/fonts/fa-regular-400.eot
  • forbidden path: public/fonts/fa-regular-400.svg
  • forbidden path: public/fonts/fa-regular-400.ttf
  • …

This malware usually gets into a branch from an infected developer machine — it rewrites commits and adds hidden files. Please:

  1. Remove all of the files/changes listed above (e.g. api.js, .vscode/, public/fonts/*, code hidden after long whitespace in config files, and node api.js in package.json scripts).
  2. Scan your machine: check ~/.vscode tasks and recently modified config files in your other projects, and rotate any tokens/keys stored on it.
  3. Push a clean commit (or recreate the branch from a fresh clone of main).

Once the branch is clean and CI passes, we'll review and merge it. 🙏

@abiolatousin-design

Copy link
Copy Markdown
Author

@mikewheeleer — this PR is ready for another review. I resolved the merge conflicts with the main branch (pushed bcee8f9).
Files changed: README.md, contracts/escrow/src/lib.rs, contracts/escrow/src/test.rs

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.

Add per-milestone due dates and let clients reclaim funds for overdue milestones

2 participants