Skip to content

fix(contracts): extend Claimable TTL and reject evaluator == provider in escrow - #105

Merged
TOMOKI977 merged 5 commits into
mainfrom
fix/95-escrow-claimable-ttl-evaluator-guard
Oct 6, 2026
Merged

TOMOKI977 merged 5 commits into
mainfrom
fix/95-escrow-claimable-ttl-evaluator-guard

Conversation

@moises-cisneros

Copy link
Copy Markdown
Contributor

Closes #95

Summary

Fixes the two escrow gaps found in the review of #78, before the Testnet redeploy in #84:

  • Claimable TTL. New permissionless extend_claimable_ttl(recipient, token) bumps the instance and the Claimable(recipient, token) entry. It does nothing if the entry does not exist, credits nothing, and emits no event. extend_ttl(job_id) is unchanged.
  • Evaluator is provider. New EscrowError::EvaluatorIsProvider = 117, returned by create_job when evaluator == provider. The check runs right after ClientIsProvider and before the registry call.

Docs are aligned with the API contract (#77): docs/architecture/api.md now states the escrow rejects evaluator = provider, and docs/verification/onchain.md explains how to keep a deferred payout alive. The SDD change is archived and the escrow spec is synced.

Acceptance criteria

  • A Claimable balance can have its TTL extended without crediting it, and a test proves it stays withdrawable after the extension (extend_claimable_ttl_restores_a_decayed_entry).
  • create_job with evaluator == provider returns the new error, and a test covers it (evaluator_cannot_be_the_provider, evaluator_is_provider_has_code_117).
  • cargo fmt, cargo clippy -D warnings, cargo test and stellar contract build pass.
  • contracts/README.md lists the new function and error.

Verification evidence

cd contracts
cargo fmt --all -- --check                     # exit 0
cargo clippy --all-targets -- -D warnings      # exit 0
cargo test                                     # escrow: 136 passed; identity-registry: 15 passed; 0 failed
stellar contract build                         # Build Complete (30 exported functions incl. extend_claimable_ttl)

Spec verification: PASS (5 requirements, 27 scenarios, all covered by passing tests).

Notes for reviewers

  • Only 4 snapshot files are new; no existing snapshot changed. On Windows, core.autocrlf makes cargo test rewrite existing snapshots with line-ending changes only. Those were discarded and are not in this PR.
  • The deployed Testnet instance does not have the new function or error until the redeploy in chore(contracts): deploy escrow on testnet and document verifiable on-chain evidence #84.
  • Out of scope, follow-ups: map code 117 in Serverpod/Flutter, refund fallback for refund_client (ADR-0005).
  • Commits: the code with its tests and snapshots, the docs, then the OpenSpec change and its archive.

… in escrow

Add permissionless extend_claimable_ttl(recipient, token) so a deferred
payout stays withdrawable, and EscrowError::EvaluatorIsProvider (117)
returned by create_job when evaluator == provider.

Refs #95
@moises-cisneros moises-cisneros added this to the Stellar Elite (Oct 10) milestone Oct 6, 2026
@moises-cisneros moises-cisneros added area: contracts Soroban smart contracts (Rust) type: chore Maintenance and tooling P1 Important, next in line labels Oct 6, 2026
@moises-cisneros moises-cisneros self-assigned this Oct 6, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Deploying puls3 with  Cloudflare Pages  Cloudflare Pages

Latest commit: a03f51a
Status: ✅  Deploy successful!
Preview URL: https://706b7e9e.puls3-4lw.pages.dev
Branch Preview URL: https://fix-95-escrow-claimable-ttl.puls3-4lw.pages.dev

View logs

@TOMOKI977 TOMOKI977 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.

Approved. The change is small and well-contained, and I couldn't find a way around the evaluator guard: verify_provider pins provider to the registry wallet and neither field changes after create_job. extend_claimable_ttl never reads or writes the balance, so leaving it permissionless is safe.

A few non-blocking follow-ups:

Tests

  • error_codes_are_stable_and_distinct still stops at 116. Adding EvaluatorIsProvider there (and dropping the standalone 117 test) keeps one source of truth, so a future duplicate of 117 gets caught.
  • The spec says the guard runs before the registry check, but evaluator_cannot_be_the_provider uses a registered agent, so it would still pass if the order flipped. A case with an unregistered agent_id expecting EvaluatorIsProvider would pin it. A third-party evaluator (neither client nor provider) being accepted is also untested.
  • In extend_claimable_ttl_restores_a_decayed_entry, the caller balance assertions prove nothing, because that address never makes the call.

Spec

  • openspec/specs/agent-escrow-lifecycle/spec.md:550 needs a blank line before ### Requirement: R15., otherwise some renderers fold the heading into the previous bullet. Requirements also read R12, R14, R13, R15.

Docs and rollout

  • Once a Claimable entry is archived, extend_claimable_ttl and withdraw no longer help. onchain.md mentions stellar contract restore but not how to build the key for that entry.
  • Nobody owns calling extend_claimable_ttl before the ~60 days run out. Worth a line on who does it (or a note in #101 so the tracker can do it later).
  • onchain.md shows the new command without the "only after the redeploy (#84)" caveat that the README has.
  • Server and Flutter should map 117 before the redeploy, so a bad create_job surfaces as a clear error instead of a generic contract failure.

@TOMOKI977 TOMOKI977 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.

Approving. Notes above are non-blocking follow-ups.

@TOMOKI977
TOMOKI977 merged commit 2663098 into main Oct 6, 2026
8 checks passed
@TOMOKI977

Copy link
Copy Markdown
Contributor

@moises-cisneros merged into main as 2663098 (squash), which closes #95. I updated the branch from main first and CI passed again. Next step on your side is the escrow redeploy (#84); please land the 117 mapping in the server and app before or together with it. The review notes above can go in a follow-up.

@moises-cisneros
moises-cisneros deleted the fix/95-escrow-claimable-ttl-evaluator-guard branch October 8, 2026 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: contracts Soroban smart contracts (Rust) P1 Important, next in line type: chore Maintenance and tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(contracts): extend Claimable TTL and reject evaluator == provider in escrow

2 participants