Skip to content

feat(contract): add a deposit-only emergency pause (ADR 0005) - #216

Merged
afeezorobsco-cyber merged 32 commits into
DocForum:mainfrom
Azintar:feat/adr-implementation-emergency-pause-that-can-only
Oct 31, 2026
Merged

afeezorobsco-cyber merged 32 commits into
DocForum:mainfrom
Azintar:feat/adr-implementation-emergency-pause-that-can-only

Conversation

@Azintar

@Azintar Azintar commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

There was no on-chain way to slow down a live bug: the only defence was telling integrators to stop. This adds a narrow lever instead — a single custodian set by the contract's constructor can block create_escrow and nothing else, so new exposure stops while every existing escrow can still be released, refunded, or timeout-refunded. Blocking outbound paths would have turned a possible loss into a certain lock, which is why the pause deliberately does not read the flag there (and the 16 new tests prove it).

Records the decision in ADR 0005, adds the role to the threat model (T11, invariant I6), and regenerates/bumps the SDK to 0.4.0 for the new pause/unpause/is_paused/get_pause_admin surface.

Closes #35

🤖 Generated with Codebuff

What changed

Which ROADMAP.md item does this close/progress?

(required — see AGENTS.md doc-update rules)

Docs updated in this PR (check all that apply)

  • ROADMAP.md
  • ARCHITECTURE.md
  • ARCHITECTURE_ESSENTIALS.md
  • PRD.md
  • N/A for this change

There was no on-chain way to slow down a live bug: the only defence was
telling integrators to stop. This adds a narrow lever instead — a single
custodian set by the contract's constructor can block `create_escrow` and
nothing else, so new exposure stops while every existing escrow can still
be released, refunded, or timeout-refunded. Blocking outbound paths would
have turned a possible loss into a certain lock, which is why the pause
deliberately does not read the flag there (and the 16 new tests prove it).

Records the decision in ADR 0005, adds the role to the threat model (T11,
invariant I6), and regenerates/bumps the SDK to 0.4.0 for the new
pause/unpause/is_paused/get_pause_admin surface.

Closes DocForum#35

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@github-actions github-actions Bot added the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 20, 2026
@github-actions

Copy link
Copy Markdown

@Azintar This PR now has merge conflicts with main, most likely because #158 (feat(contract): sponsored funding: a funder distinct from the refund …) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-escrow.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared files like ROADMAP.md and ARCHITECTURE*.md. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

codebuff-team and others added 2 commits October 21, 2026 17:05
Adds a constructor-set custodian that can pause every deposit path
(create_escrow and its variants, plus top_up) and nothing else, so new
exposure stops while existing escrows can still be released, refunded or
timeout-refunded. Pause/unpause are custodian-only, non-idempotent, and emit
Paused/Unpaused events; is_paused/get_pause_admin are read-only.

Rebased onto current main: the constructor is merged with the existing
token allowlist (__constructor(allowed_tokens, pause_admin)), top_up is
gated as the ADR requires of any deposit path, error codes are 26-28 to
avoid colliding with existing codes, and the ADR is renumbered to 0011 so
it does not clash with the protocol-fee ADR.
Keeps the branch fast-forwardable: this commit's tree is exactly the
rebased (ADR 0011) tree and its second parent is that rebase, so main is an
ancestor of the branch and the PR diff only contains this change.
@drips-wave

drips-wave Bot commented Oct 21, 2026

Copy link
Copy Markdown

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

@github-actions github-actions Bot added needs-rebase Has merge conflicts with main; the author needs to rebase and removed needs-rebase Has merge conflicts with main; the author needs to rebase labels Oct 21, 2026
@github-actions

Copy link
Copy Markdown

@Azintar This PR now has merge conflicts with main, most likely because #152 (feat(contract): payer cancellation window before the payee accepts) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-escrow.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

@github-actions github-actions Bot removed the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 22, 2026
@github-actions github-actions Bot added the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 22, 2026
@github-actions

Copy link
Copy Markdown

@Azintar This PR now has merge conflicts with main, most likely because #180 (feat(sdk): batch create and batch settle support) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-escrow.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

@github-actions

Copy link
Copy Markdown

@Azintar This PR now has merge conflicts with main, most likely because #193 (feat(sdk): milestone escrow support) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-escrow.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

@github-actions github-actions Bot added needs-rebase Has merge conflicts with main; the author needs to rebase and removed needs-rebase Has merge conflicts with main; the author needs to rebase labels Oct 23, 2026
@github-actions

Copy link
Copy Markdown

@Azintar This PR now has merge conflicts with main, most likely because #257 (feat(contract): pooled escrows funded by multiple payers with pro-rata refunds) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-escrow.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Azintar CI is failing on this branch against the latest main, so it can't be merged yet. The errors from the latest run:

TypeScript SDK (Bun), TypeScript SDK (Node 20), TypeScript SDK (Node 24)

src/generated/contract-client.ts(130,8): error TS1005: ',' expected.
src/generated/contract-client.ts(130,14): error TS1005: ',' expected.
src/generated/contract-client.ts(130,19): error TS1005: ',' expected.
src/generated/contract-client.ts(130,23): error TS1005: ',' expected.
src/generated/contract-client.ts(130,30): error TS1005: ',' expected.
src/generated/contract-client.ts(130,35): error TS1005: ',' expected.
src/generated/contract-client.ts(130,40): error TS1005: ',' expected.
src/generated/contract-client.ts(130,57): error TS1005: ',' expected.

Also failing: React hooks package, TypeScript SDK (Node 22), Soroban contract (test + wasm build), TypeScript SDK (Deno), TypeScript SDK (Chromium), SDK bindings match contract WASM.

sdk/src/generated/contract-client.ts is broken at line 130 (invalid characters, probably leftover conflict markers or a hand merge). Don't hand-edit or hand-merge it. Regenerate it:

cd contracts/escrow && cargo build --target wasm32v1-none --release
stellar contract bindings typescript --wasm target/wasm32v1-none/release/docforum_escrow.wasm --output-dir /tmp/escrow-bindings --overwrite
cp /tmp/escrow-bindings/src/index.ts ../../sdk/src/generated/contract-client.ts

This PR also conflicts with main again, so please rebase first, then fix the above.

@github-actions github-actions Bot removed the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 23, 2026
The last merge of main (DocForum#257 pooled escrows, DocForum#193/DocForum#248 SDK work) left the
branch broken:

- contract: `DataKey::Pooled`/`Contribution` had been spliced into the
  `Unpaused` event struct; restore them to `DataKey`.
- contract: `Paused`/`AlreadyPaused`/`NotPaused` collided with
  `NotPooled`/`FundingDeadlinePassed`/`FundingTargetReached` (26-28).
  Main's codes keep their on-chain values; the pause codes are appended
  as 35/36/37 (docs, ADR 0011, README, threat model, ROADMAP, changelog
  updated).
- contract: gate the new pooled deposit paths (`create_pooled_escrow`,
  `contribute`) on the pause; `claim_refund` and `release` stay ungated.
  Three new tests in tests/pause.rs cover this.
- tests: main's new tests (cancel, pooled, model, malicious_token)
  registered the contract with the old one-argument constructor; pass a
  pause admin. Snapshots regenerated with `cargo test`.
- sdk: regenerate src/generated/contract-client.ts with the pinned
  stellar CLI 28.1.0 (it contained a broken hand merge); close the
  unterminated `getPauseAdmin` method in src/index.ts; drop the duplicate
  `test:unit` script key in package.json.
- ci: the Go SDK local-network deploy passes `--pause_admin`.
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Malware scan: passed, with notes for the reviewer

Nothing malicious was detected in d1ac44c. These changes touch sensitive areas and should get a careful look before CI is approved:

Where Rule Why
.github/workflows/sdk-go.yml:59 workflow-change Changes a CI workflow; a maintainer must review before approving runs.

@github-actions github-actions Bot added the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 24, 2026
@github-actions

Copy link
Copy Markdown

@Azintar This PR now has merge conflicts with main, most likely because #260 (feat(perf): profile and optimize status reads) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-escrow.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

…tion-emergency-pause-that-can-only

# Conflicts:
#	contracts/escrow/test_snapshots/acceptance_requires_the_payee_and_only_works_while_funded.1.json
#	contracts/escrow/test_snapshots/callback_cannot_reenter_create_escrow.1.json
#	contracts/escrow/test_snapshots/callback_cannot_reenter_refund.1.json
#	contracts/escrow/test_snapshots/callback_cannot_reenter_release.1.json
#	contracts/escrow/test_snapshots/callback_error_reverts_release_but_does_not_block_refund.1.json
#	contracts/escrow/test_snapshots/cancel_after_release_is_rejected.1.json
#	contracts/escrow/test_snapshots/cancel_after_releaser_refund_is_rejected.1.json
#	contracts/escrow/test_snapshots/cancel_after_timeout_refund_is_rejected.1.json
#	contracts/escrow/test_snapshots/cancel_is_not_available_without_requires_acceptance.1.json
#	contracts/escrow/test_snapshots/cancel_only_returns_that_escrows_amount.1.json
#	contracts/escrow/test_snapshots/cancel_pays_the_sponsored_refund_to_not_the_funder.1.json
#	contracts/escrow/test_snapshots/cancel_requires_the_payers_signature.1.json
#	contracts/escrow/test_snapshots/cancel_stays_rejected_after_accept_even_much_later.1.json
#	contracts/escrow/test_snapshots/cancel_still_works_after_refund_after_has_passed_if_still_funded.1.json
#	contracts/escrow/test_snapshots/claim_refund_emits_an_event.1.json
#	contracts/escrow/test_snapshots/claiming_requires_the_contributors_signature.1.json
#	contracts/escrow/test_snapshots/configured_allowlist_accepts_listed_token_and_rejects_unlisted_token.1.json
#	contracts/escrow/test_snapshots/contribute_emits_an_event.1.json
#	contracts/escrow/test_snapshots/contribute_rejects_lying_transfer.1.json
#	contracts/escrow/test_snapshots/contribute_rejects_short_delivery.1.json
#	contracts/escrow/test_snapshots/contributor_cannot_claim_another_contributors_funds.1.json
#	contracts/escrow/test_snapshots/create_bounds_the_releaser_set_size.1.json
#	contracts/escrow/test_snapshots/create_escrow_accepts_deadline_strictly_in_the_future.1.json
#	contracts/escrow/test_snapshots/create_escrow_assigns_sequential_ids.1.json
#	contracts/escrow/test_snapshots/create_escrow_locks_funds_and_reports_funded.1.json
#	contracts/escrow/test_snapshots/create_escrow_rejects_condition_ref_that_is_too_long.1.json
#	contracts/escrow/test_snapshots/double_cancel_is_rejected_and_pays_out_once.1.json
#	contracts/escrow/test_snapshots/double_claim_is_rejected.1.json
#	contracts/escrow/test_snapshots/double_refund_pays_refund_to_once.1.json
#	contracts/escrow/test_snapshots/duplicate_approvals_from_one_releaser_cannot_satisfy_the_threshold.1.json
#	contracts/escrow/test_snapshots/each_listed_approver_must_actually_authorize_the_invocation.1.json
#	contracts/escrow/test_snapshots/empty_allowlist_preserves_open_token_behavior.1.json
#	contracts/escrow/test_snapshots/escrow_without_requires_acceptance_still_releases_and_refunds_as_before.1.json
#	contracts/escrow/test_snapshots/explicit_refund_to_equal_to_payer_behaves_like_the_default.1.json
#	contracts/escrow/test_snapshots/failed_claim_leaves_the_contribution_intact.1.json
#	contracts/escrow/test_snapshots/failed_payout_leaves_the_escrow_funded.1.json
#	contracts/escrow/test_snapshots/failed_round_refunds_every_contributor_exactly.1.json
#	contracts/escrow/test_snapshots/funder_calling_refund_after_the_deadline_cannot_steer_the_money_to_itself.1.json
#	contracts/escrow/test_snapshots/get_escrow_exposes_the_stored_parties_and_deadline.1.json
#	contracts/escrow/test_snapshots/get_escrow_reports_no_deadline_when_none_was_set.1.json
#	contracts/escrow/test_snapshots/invalid_contributions_are_rejected.1.json
#	contracts/escrow/test_snapshots/legacy_creation_keeps_acceptance_opt_out.1.json
#	contracts/escrow/test_snapshots/multiple_contributors_recorded_independently.1.json
#	contracts/escrow/test_snapshots/neither_funder_nor_refund_to_may_trigger_a_refund_before_the_deadline.1.json
#	contracts/escrow/test_snapshots/no_contributor_cap_each_claim_is_independent.1.json
#	contracts/escrow/test_snapshots/non_member_approver_is_rejected.1.json
#	contracts/escrow/test_snapshots/omitted_refund_to_defaults_to_payer.1.json
#	contracts/escrow/test_snapshots/omitted_refund_to_timeout_refund_still_goes_to_payer.1.json
#	contracts/escrow/test_snapshots/only_the_stored_payer_may_cancel.1.json
#	contracts/escrow/test_snapshots/opted_in_contract_payee_receives_release_callback.1.json
#	contracts/escrow/test_snapshots/ordinary_escrows_are_unaffected.1.json
#	contracts/escrow/test_snapshots/partial_funding_records_and_blocks_release.1.json
#	contracts/escrow/test_snapshots/payer_cancel_before_accept_refunds_payer_in_full.1.json
#	contracts/escrow/test_snapshots/pooled_creation_respects_the_token_allowlist.1.json
#	contracts/escrow/test_snapshots/pooled_creation_validation.1.json
#	contracts/escrow/test_snapshots/push_paths_and_top_up_reject_pooled_escrows.1.json
#	contracts/escrow/test_snapshots/quorum_escrow_stores_the_releaser_set_and_threshold.1.json
#	contracts/escrow/test_snapshots/quorum_release_invokes_opted_in_contract_payee.1.json
#	contracts/escrow/test_snapshots/race_accept_lands_first_then_cancel_fails_and_payee_keeps_the_escrow.1.json
#	contracts/escrow/test_snapshots/race_cancel_lands_first_then_accept_fails_and_payer_keeps_the_funds.1.json
#	contracts/escrow/test_snapshots/reaching_the_target_releases_the_pooled_total.1.json
#	contracts/escrow/test_snapshots/reentrant_transfer_cannot_double_release.1.json
#	contracts/escrow/test_snapshots/refund_entitlements_are_order_independent.1.json
#	contracts/escrow/test_snapshots/refund_entitlements_are_order_independent.2.json
#	contracts/escrow/test_snapshots/refund_entitlements_are_order_independent.3.json
#	contracts/escrow/test_snapshots/refund_rejects_after_release.1.json
#	contracts/escrow/test_snapshots/refund_rejects_unauthorized_caller.1.json
#	contracts/escrow/test_snapshots/refund_to_is_fixed_at_creation_and_visible_via_get_escrow.1.json
#	contracts/escrow/test_snapshots/refund_transfers_funds_back_to_payer_and_marks_refunded.1.json
#	contracts/escrow/test_snapshots/refund_with_approvals_rejects_duplicates_and_short_thresholds.1.json
#	contracts/escrow/test_snapshots/refund_with_approvals_returns_funds_to_the_payer.1.json
#	contracts/escrow/test_snapshots/release_and_refund_can_never_share_funds.1.json
#	contracts/escrow/test_snapshots/release_is_rejected_before_time_and_allowed_at_the_exact_boundary.1.json
#	contracts/escrow/test_snapshots/release_lock_does_not_restrict_releaser_refunds.1.json
#	contracts/escrow/test_snapshots/release_rejects_after_refund.1.json
#	contracts/escrow/test_snapshots/release_rejects_double_release.1.json
#	contracts/escrow/test_snapshots/release_rejects_unauthorized_caller.1.json
#	contracts/escrow/test_snapshots/release_still_pays_the_payee_not_refund_to.1.json
#	contracts/escrow/test_snapshots/release_time_equal_to_creation_time_is_valid_and_releasable_immediately.1.json
#	contracts/escrow/test_snapshots/release_time_equal_to_refund_deadline_is_valid.1.json
#	contracts/escrow/test_snapshots/release_transfers_funds_to_payee_and_marks_released.1.json
#	contracts/escrow/test_snapshots/release_wins_at_the_deadline_and_timeout_refund_then_fails.1.json
#	contracts/escrow/test_snapshots/release_with_approvals_is_gated_by_full_funding_too.1.json
#	contracts/escrow/test_snapshots/release_with_exactly_threshold_distinct_approvals_pays_the_payee.1.json
#	contracts/escrow/test_snapshots/release_with_fewer_than_threshold_approvals_is_rejected.1.json
#	contracts/escrow/test_snapshots/release_with_more_than_threshold_approvals_succeeds.1.json
#	contracts/escrow/test_snapshots/releaser_can_still_release_after_the_deadline.1.json
#	contracts/escrow/test_snapshots/releaser_cannot_pay_out_after_cancel.1.json
#	contracts/escrow/test_snapshots/releaser_refund_goes_to_refund_to_not_the_funder.1.json
#	contracts/escrow/test_snapshots/releaser_refund_still_works_before_deadline.1.json
#	contracts/escrow/test_snapshots/releasers_can_still_release_after_the_deadline.1.json
#	contracts/escrow/test_snapshots/repeated_contributions_accumulate_per_payer.1.json
#	contracts/escrow/test_snapshots/required_acceptance_blocks_release_until_payee_accepts.1.json
#	contracts/escrow/test_snapshots/rotation_rejects_contract_and_payee_as_new_releaser.1.json
#	contracts/escrow/test_snapshots/rotation_rejects_wrong_releaser_and_non_funded_escrows.1.json
#	contracts/escrow/test_snapshots/rotation_requires_both_stored_parties_and_updates_the_releaser.1.json
#	contracts/escrow/test_snapshots/settled_approvals_cannot_be_replayed.1.json
#	contracts/escrow/test_snapshots/settled_escrow_cannot_be_refunded_to_refund_to_afterwards.1.json
#	contracts/escrow/test_snapshots/single_caller_release_on_a_quorum_escrow_needs_the_approval_path.1.json
#	contracts/escrow/test_snapshots/single_releaser_escrow_behaves_as_a_one_of_one_quorum.1.json
#	contracts/escrow/test_snapshots/the_beneficiary_refund_to_never_has_to_sign.1.json
#	contracts/escrow/test_snapshots/timeout_refund_at_the_exact_deadline_goes_to_refund_to.1.json
#	contracts/escrow/test_snapshots/timeout_refund_by_a_stranger_goes_to_refund_to.1.json
#	contracts/escrow/test_snapshots/timeout_refund_by_stranger_succeeds_after_deadline.1.json
#	contracts/escrow/test_snapshots/timeout_refund_by_stranger_succeeds_at_the_exact_deadline.1.json
#	contracts/escrow/test_snapshots/timeout_refund_cannot_pay_anyone_but_the_payer.1.json
#	contracts/escrow/test_snapshots/timeout_refund_fails_after_release.1.json
#	contracts/escrow/test_snapshots/timeout_refund_fails_after_releaser_refund.1.json
#	contracts/escrow/test_snapshots/timeout_refund_rejected_before_deadline.1.json
#	contracts/escrow/test_snapshots/timeout_refund_still_needs_no_approvals_on_a_quorum_escrow.1.json
#	contracts/escrow/test_snapshots/timeout_refund_wins_at_the_deadline_and_release_then_fails.1.json
#	contracts/escrow/test_snapshots/top_up_adds_funds_to_the_same_funded_escrow.1.json
#	contracts/escrow/test_snapshots/top_up_after_cancel_is_rejected.1.json
#	contracts/escrow/test_snapshots/top_up_before_accept_is_fully_returned_by_cancel.1.json
#	contracts/escrow/test_snapshots/top_up_emits_an_event.1.json
#	contracts/escrow/test_snapshots/top_up_rejects_invalid_payer_amount_overflow_and_settled_state.1.json
#	contracts/escrow/test_snapshots/two_escrows_keep_their_own_refund_to.1.json
#	contracts/escrow/test_snapshots/without_deadline_releaser_refund_still_works.1.json
#	contracts/escrow/test_snapshots/without_deadline_stranger_refund_stays_unauthorized_even_forever_after.1.json
#	docs/testnet-deployments.md
@github-actions github-actions Bot added needs-rebase Has merge conflicts with main; the author needs to rebase and removed needs-rebase Has merge conflicts with main; the author needs to rebase labels Oct 24, 2026
@github-actions github-actions Bot added the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 27, 2026
@github-actions

Copy link
Copy Markdown

@Azintar This PR now has merge conflicts with main, most likely because #247 (feat(sdk): add multisig releaser setup helpers with lock-out validation) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-escrow.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

…-can-only

Resolve docs/threat-model.md (keep main's multisig-SDK note on the releaser
item and this PR's new pause-custodian item) and regenerate
sdk/src/generated/contract-client.ts from the merged contract with stellar
CLI 28.1.0 (scripts/check-generated-bindings.sh passes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

@Azintar This PR now has merge conflicts with main, most likely because #254 (feat(contract): batch release and refund for fast settlement of many escrows) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-escrow.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Azintar I resolved this PR's earlier conflicts with main (commit 1a8e553: docs/threat-model.md, plus SDK bindings regenerated with stellar CLI 28.1.0). Since then #254 (batch settle_many) has merged, and this PR conflicts again, this time in contract code:

README.md
contracts/escrow/src/lib.rs
contracts/escrow/tests/liabilities.rs
sdk/src/generated/contract-client.ts

What's needed:

  1. lib.rs: merge your emergency pause with settle_many. Decide whether settle_many's release/refund ops need the same pause rules as single release/refund (per ADR 0011, the pause stops new deposits but must never block outbound paths).
  2. CONTRACT_VERSION: main is now 2.2.0 (from feat(contract): batch release and refund for fast settlement of many escrows #254), so this PR needs 2.3.0 or higher.
  3. Bindings: regenerate sdk/src/generated/contract-client.ts with stellar CLI 28.1.0 (scripts/check-generated-bindings.sh shows the exact commands), and refresh any test_snapshots/ that change.

Please git pull first so you start from my merge commit, then merge main, run cargo test in contracts/escrow, and push.

Azintar and others added 2 commits October 27, 2026 19:51
…bump to 2.3.0

Follow-up to the upstream main merge (DocForum#254). Per ADR 0011 the pause stops new
deposits only and never blocks outbound paths, so settle_many's release and
refund ops ignore the pause flag exactly like single release/refund
(invariant I8). Documents this in lib.rs, README and the threat model, adds
pause tests showing settle_many release, refund and a mixed batch all succeed
while paused (with their snapshots), bumps CONTRACT_VERSION to 2.3.0 (main
is 2.2.0) and applies cargo fmt.
@github-actions github-actions Bot removed the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 27, 2026
@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Azintar This branch was updated with main through GitHub's web conflict editor (e73f035), and that resolution dropped your three pause error variants from pub enum Error, while the code still uses them. The contract no longer compiles:

error[E0599]: no variant ... named `Paused` found for enum `Error`         --> src/lib.rs:683:31
error[E0599]: no variant ... named `AlreadyPaused` found for enum `Error`  --> src/lib.rs:1699:31
error[E0599]: no variant ... named `NotPaused` found for enum `Error`      --> src/lib.rs:1718:31

Please git pull, then re-add Paused, AlreadyPaused and NotPaused to Error, numbered after the highest code currently on main. Codes are append-only, so don't renumber existing ones. CONTRACT_VERSION must also be above main's current 2.3.0. Then run cargo test in contracts/escrow, regenerate the SDK bindings with stellar CLI 28.1.0, and push.

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Azintar Heads-up: #268 just changed how contract PRs work in this repo. Your PR changes contracts/escrow/src/lib.rs, so CI's new "Contract changes use a fragment, not a version bump" step will fail it until you make these changes (details in contract-changes.d/README.md):

  1. Don't edit CONTRACT_VERSION when you merge main (currently 2.3.0). Keep main's line as it is.

  2. Add a fragment, e.g. contract-changes.d/35-emergency-pause.md:

    bump: minor
    ---
    Issue #35: one-paragraph summary of the contract change.

    Use patch for a behaviour fix with no interface change, minor for new entry points, arguments, events or errors, and major for breaking changes.

  3. Re-add your pause errors with provisional codes: Paused = 3500, AlreadyPaused = 3501, NotPaused = 3502 (issue [Phase E5] ADR + implementation: emergency pause that can only stop new escrows #35 × 100 + n). The web-editor merge I mentioned earlier dropped them, so this fixes that compile error too. The fold assigns the final numbers.

This should also make your next merge from main much easier: the version line was the one thing every contract PR conflicted on.

@github-actions github-actions Bot added the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 28, 2026
@github-actions

Copy link
Copy Markdown

@Azintar This PR now has merge conflicts with main, most likely because #199 (feat(contract): payee rights transfer: payee reassigns future payout to a new address) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-escrow.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

Azintar and others added 2 commits October 28, 2026 19:21
The last merge of main (DocForum#169/DocForum#199) left the branch uncompilable and its
tests failing:

- `Error` lost `Paused`, `AlreadyPaused` and `NotPaused` while `lib.rs`
  still returns them (E0599). Re-added with the provisional codes
  3500-3502 that contract-changes.d/README.md asks for, since main already
  spent 35 (`InvalidFee`) and 36 (`Undeliverable`); the maintainer fold
  assigns the final numbers. README, ADR 0011, ROADMAP, the threat model
  and the changelog fragment no longer claim 36-38.
- `use soroban_sdk::{...}` was spliced into itself, so every imported name
  was defined twice (E0252).
- main's newer `tests/transfer_payee.rs` and `tests/undeliverable.rs`
  still registered the contract with the old one-argument constructor, so
  all 14 of their tests panicked ("invalid number of input arguments: 2
  expected, got 1"). They now pass a pause admin and their snapshots are
  regenerated.
- Added the required `contract-changes.d/35-emergency-pause.md` fragment
  (`bump: minor`); `CONTRACT_VERSION` stays at main's 2.3.0, as the new CI
  rule requires.

`cargo test` passes for every suite in contracts/escrow (pause 23,
create_escrow 7, release_refund 8, timeout_refund 17, top_up 3, cancel 18,
payee_acceptance 3, pooled 19, settle_many 13, liabilities 14,
protocol_fee 17, quorum 19, transfer_payee 12, undeliverable 2,
token_allowlist 2, token_edge_cases 1, malicious_token 7,
sponsored_refund 16, releaser_rotation 3, release_callback 6,
time_locked_release 5, model 4).

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
@github-actions github-actions Bot removed the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 28, 2026
@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Azintar Thanks for repairing the pause merge. The contract checks now pass. What's left is sdk/src/generated/contract-client.ts, which was merged by hand and is no longer valid TypeScript. Line 606 ends get_pause_admin, and the /** that should open the next doc comment (for transfer_payee) is missing, so every SDK job fails:

src/generated/contract-client.ts(607,4): error TS1131: Property or signature expected.
src/generated/contract-client.ts(607,16): error TS1005: ';' expected.
...

Don't fix it by hand. Regenerate the file from your merged contract with stellar CLI 28.1.0:

cd contracts/escrow && cargo build --target wasm32v1-none --release
stellar contract bindings typescript --wasm target/wasm32v1-none/release/docforum_escrow.wasm --output-dir /tmp/escrow-bindings --overwrite
cp /tmp/escrow-bindings/src/index.ts ../../sdk/src/generated/contract-client.ts
./scripts/check-generated-bindings.sh   # must print OK

Then push. Everything else on this PR is green.

@Azintar

Azintar commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

@afeezorobsco-cyber
Awaiting review sir

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Azintar The latest merge from main broke two things:

  1. sdk/src/generated/contract-client.ts is malformed at line 607, where the /** opening the transfer_payee doc comment was lost, so every TypeScript SDK job fails to compile:
    src/generated/contract-client.ts(607,4): error TS1131: Property or signature expected.
    
    Don't hand-merge this file. Regenerate it from the contract WASM with scripts/check-generated-bindings.sh (stellar CLI pinned in scripts/stellar-cli-version) so "SDK bindings match contract WASM" passes too.
  2. contracts/escrow/tests/events.rs (from main) doesn't pass pause_admin: it still registers the contract with (Vec::<Address>::new(&env),), so the constructor fails (Error(WasmVm, InvalidAction)) and all 7 event tests panic. Update those env.register(...) calls (lines 88, 166, 340, 488, 550) to pass a pause admin, as you did in the other test files.

Azintar and others added 2 commits October 30, 2026 18:12
…ts.rs

The merge of main (DocForum#238, lifecycle events) left two jobs failing:

- `sdk/src/generated/contract-client.ts` was hand-mangled: the `/**` that
  opens the `transfer_payee` doc block was lost (TS1131), and the file
  predated the provisional pause error codes. It is now exactly what the
  pinned stellar CLI (28.1.0, scripts/stellar-cli-version) generates from
  the current contract WASM, so "SDK bindings match contract WASM" passes
  too. Never hand-edited.
- main's `contracts/escrow/tests/events.rs` still registered the contract
  with the one-argument constructor, so its 13 tests panicked with
  `Error(WasmVm, InvalidAction)` ("2 expected, got 1"). All five
  `env.register` sites now pass a pause admin, and their snapshots are
  regenerated for the `PauseAdmin`/`Paused` instance entries.

`cargo test` passes for every suite in contracts/escrow (events 13,
pause 23, create_escrow 7, release_refund 8, timeout_refund 17, top_up 3,
cancel 18, payee_acceptance 3, pooled 19, settle_many 13, liabilities 14,
protocol_fee 17, quorum 19, transfer_payee 12, undeliverable 2,
token_allowlist 2, token_edge_cases 1, malicious_token 7,
sponsored_refund 16, releaser_rotation 3, release_callback 6,
time_locked_release 5, model 4).

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
Brings in DocForum#238 (lifecycle events) and DocForum#270, the contract-change fold that
bumped CONTRACT_VERSION to 2.4.0 and renumbered main's provisional
`InvalidNewPayee` from 4500 to 37.

The only conflict was sdk/src/generated/contract-client.ts, resolved as the
repo requires: regenerated from the merged contract WASM with the pinned
stellar CLI 28.1.0 (scripts/stellar-cli-version), never hand-merged. The
contract-changes.d and changelog.d fragments that DocForum#270 folded are dropped;
this PR's own 35-emergency-pause fragments stay, and the pause error codes
stay provisional (3500-3502) for the next fold.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
@Azintar

Azintar commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

@afeezorobsco-cyber please review
I applied the requested fix

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Azintar Thanks, that fixed it: the contract tests, the events.rs constructor calls and all TypeScript SDK jobs now pass. One check is still red, SDK bindings match contract WASM. When you resolved the contract-client.ts conflict, the PayeeRefunded event spec entry ("AAAABQAAAEJJZGVudGlmaWVzIHZvbHVudGFyeSByZWZ1bmRz…", from #40) ended up in the wrong position in the ContractSpec([...]) list:

@@ -757,12 +757,12 @@
-        "AAAABQAAAEJJZGVudGlmaWVzIHZvbHVudGFyeSByZWZ1bmRzIH…   (committed: before the function entries)
         "AAAAAAAAAftCbG9ja3MgbmV3IGRlcG9zaXRzIChgY3JlYXRlX2…
         …
         "AAAAAAAAAHVBZGRzIGZ1bmRzIHRvIGEgZnVuZGVkIGVzY3Jvdy…
+        "AAAABQAAAEJJZGVudGlmaWVzIHZvbHVudGFyeSByZWZ1bmRzIH…   (generated: here)

Please don't reorder it by hand. Regenerate the file with the pinned CLI (scripts/stellar-cli-version, 28.1.0) using the steps that scripts/check-generated-bindings.sh prints, and commit the result. This is the last failing check; once it's green the PR can merge.

The bindings committed with the merge were generated from a WASM built
with the sandbox's stable Rust (1.99), but the repo pins 1.96 in
rust-toolchain.toml and CI builds with it. The compiler changes the
order of the ContractSpec entries in the WASM, so the committed file
had the PayeeRefunded event spec in a different slot than CI's
regeneration and "SDK bindings match contract WASM" failed.

Rebuilt the WASM with the pinned 1.96.0 toolchain and regenerated with
stellar CLI 28.1.0 as scripts/check-generated-bindings.sh does, so the
diff is only that one entry moving; the script now reports OK.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
@Azintar

Azintar commented Oct 31, 2026

Copy link
Copy Markdown
Contributor Author

@afeezorobsco-cyber pr is now mergeable

@afeezorobsco-cyber afeezorobsco-cyber 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.

Malware scan clean, all checks green, bindings regenerated. Thanks!

@afeezorobsco-cyber
afeezorobsco-cyber merged commit f9df83b into DocForum:main Oct 31, 2026
15 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.

[Phase E5] ADR + implementation: emergency pause that can only stop new escrows

3 participants