Skip to content

[Phase E5] Version escrow storage and migrate legacy records - #156

Open
damilare0813 wants to merge 15 commits into
DocForum:mainfrom
damilare0813:fix/issue-37
Open

damilare0813 wants to merge 15 commits into
DocForum:mainfrom
damilare0813:fix/issue-37

Conversation

@damilare0813

@damilare0813 damilare0813 commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

[Phase E5] Version escrow storage and migrate legacy records

Closes #37

Problem

Soroban persists a #[contracttype] struct as an ScVal::Map keyed by
field name. Every time EscrowData has gained a field — refund_after
(ADR 0004), the releaser set and quorum threshold (ADR 0007), the
callback/acceptance flags, and now refund_to (ADR 0009) and
release_not_before — a reader built for the new shape fails to decode an
older record, because the map's key set has to match the struct exactly.
There was no explicit policy for reading old records or for what happens
when a layout is neither the current shape nor a recognized old one.

Implementation

  • Persistent escrow records are now written as StoredEscrowData, a
    tagged enum (V1..V4) of version-specific structs. New writes
    always use V4
    , the current 14-field record (refund_to and
    release_not_before included). V1-V3 stay around only to decode
    old records; their field sets never change again.
  • load_escrow additionally recognizes the exact bare, untagged
    ScVal::Map shapes written before this scheme existed: 7 fields
    (pre-ADR-0004), 8 fields (pre-releaser-sets), 12 fields (pre-refund_to/
    release_not_before), and the current untagged 14-field map. Any other
    shape — including a tagged enum variant that doesn't decode, or
    anything else — fails closed with the new Error::UnsupportedStorageVersion
    (code 35, the next free discriminant; it does not collide with main's
    InvalidReleaser = 24).
  • Migration is on write, not on read: get_status/get_escrow never
    mutate storage. The next state-changing call on a given escrow
    (release, refund, refund_with_approvals, cancel, accept,
    rotate_releaser, top_up, or a pooled contribute/claim_refund)
    writes the record back as tagged V4 through a single save_escrow
    helper, so every write path uses the same tagged layout — there is no
    remaining call site that writes the untagged shape.
  • Covers every record type main now has, including pooled escrows
    (issue [Phase E5] Pooled escrows funded by multiple payers with pro-rata refunds #113): create_pooled_escrow builds and stores its EscrowData
    through the same save_escrow path, so a pooled escrow's body is
    always written as V4 from the start. There is no older pooled layout
    to migrate — create_pooled_escrow never existed before this scheme.
    Pooled escrows' separate Pooled and Contribution records are
    untouched — they are not part of StoredEscrowData.
  • Status read key (issue [Phase E7] Storage and resource optimisation guided by benchmarks #98): main added a dedicated
    DataKey::Status entry so get_status can skip decoding the full
    body. That key is written by the same save_status helper everywhere
    the escrow status changes (creation and settlement). get_status reads
    it directly when present, and falls back to the versioned loader (with
    the same migration-on-write guarantee) for any record predating that
    key — covered by a new test,
    legacy_record_without_status_key_reports_status_from_the_escrow_body.
  • No entry point signature changed. The only public-surface change is the
    new UnsupportedStorageVersion error variant, so
    sdk/src/generated/contract-client.ts was regenerated with the pinned
    Stellar CLI (28.1.0) — the only diff against main's bindings is that
    one error entry.
  • docs/adr/0008 and the "Persistent storage layout policy" note in
    ARCHITECTURE_ESSENTIALS.md are updated to describe the current V4
    layout, the four recognized pre-version map shapes, and how pooled
    escrows and the status key fit in (they previously described an
    earlier, now-superseded V3/three-shape design from before this branch
    picked up main's pooled-escrow and status-key work).
  • The changelog.d/37-versioned-storage-layout.md fragment (not
    ROADMAP.md — see changelog.d/README.md) is updated to match.
    ROADMAP.md itself is unchanged from main; issue [Phase E5] Versioned storage layout and a migration strategy for EscrowData #37 has no existing
    checklist line to tick there.

Merging with main

This branch previously conflicted with main after #257 (pooled
escrows) and #260 (the status read key) landed there. This PR now merges
origin/main and resolves both conflicts by keeping main's behavior and
folding it into the versioned-storage scheme:

  • Every one of main's direct env.storage().persistent().set(&DataKey::Escrow(...), ...) /
    ...set(&DataKey::Status(...), ...) call sites (in create_pooled_escrow,
    create_escrow_inner, and settle) now goes through save_escrow/
    save_status instead, so pooled-escrow creation and every settlement
    write the tagged V4 layout and the status key together.
  • ARCHITECTURE_ESSENTIALS.md's "Persistent storage layout policy" note
    (added by this branch) and main's custom-releaser-account paragraph
    are both kept, in main's order.

Validation

  • scripts/check-generated-bindings.sh with the pinned Stellar CLI
    (28.1.0): bindings match the rebuilt contract WASM, no diff.
  • cargo test in contracts/escrow: full suite green, including new and
    updated tests/storage_migration.rs cases (legacy 7/8/12-field maps,
    tagged V1/V2, the status-key fallback, and a pooled-escrow write
    check). Snapshot updates committed; a second cargo test run leaves the
    working tree clean.
  • cargo fmt --check, cargo clippy --all-targets: no errors. cargo fmt --check still reports the same pre-existing diffs that main
    itself has (benches/resource_profile.rs and a handful of lines in
    src/lib.rs/tests unrelated to this change) — confirmed byte-identical
    to main's own copies of those files, so this isn't something this PR
    introduced or needs to fix.
  • cargo build --target wasm32v1-none --release: succeeds.
  • SDK: npm ci --ignore-scripts, npm run typecheck, npm run build,
    npm run test:offline (64 tests) and npm run test:unit (56 tests) all
    pass.

Closes #37

@drips-wave

drips-wave Bot commented Oct 16, 2026

Copy link
Copy Markdown

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

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@damilare0813

This PR has merge conflicts with main, which has moved on since this branch was created. Please rebase onto the latest main (or merge main into your branch), resolve the conflicts, and push. CI will then re-run, and the PR can be merged once it's conflict-free, CI is green and it's been reviewed. Thanks!

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@damilare0813 Thanks for the PR. It can't be merged yet. To unblock it:

CI is failing. Here's what broke:

Soroban contract (test + wasm build):

test current_eight_field_map_is_read_and_migrated_on_refund ... FAILED
thread 'current_eight_field_map_is_read_and_migrated_on_refund' (4891) panicked at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/soroban-env-host-27.0.1/src/host.rs:910:9:
HostError: Error(WasmVm, InvalidAction)
3: [Failed Diagnostic Event (not emitted)] contract:CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M, topics:[log], data:["caught panic 'called `Result::unwrap()` on an `Err` value: HostError: Error(Object, Un

Please fix these errors and run the same steps locally before pushing (npm run typecheck && npm test && npm run build, or cargo test for contracts).

Merge conflicts: this branch conflicts with main. Please rebase onto the latest main (git fetch upstream && git rebase upstream/main), resolve the conflicts (often ROADMAP.md, ARCHITECTURE*.md or prisma/schema.prisma), and force-push.

Push to this same branch and CI will re-run. Once it's green and conflict-free, it'll be reviewed for merge.

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

Copy link
Copy Markdown
Contributor Author

@afeezorobsco-cyber I resolved the conflicts with main and pushed the update. The escrow contract test suite passes. Please review and merge when ready.

@github-actions

Copy link
Copy Markdown

@damilare0813 This PR now has merge conflicts with main, most likely because #183 (feat(contract): add optional release callback) 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.

# Conflicts:
#	ROADMAP.md
#	contracts/escrow/src/lib.rs
@damilare0813

Copy link
Copy Markdown
Contributor Author

@afeezorobsco-cyber I resolved the merge conflicts and verified the storage migration regression tests pass. The PR description now has a standalone Closes #37 reference. Please review and merge when ready.

@github-actions

Copy link
Copy Markdown

@damilare0813 This PR now has merge conflicts with main, most likely because #196 (feat(sdk): fee estimation and fee-bump sponsorship helpers) 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.

# Conflicts:
#	ROADMAP.md
#	contracts/escrow/src/lib.rs
@damilare0813

Copy link
Copy Markdown
Contributor Author

@afeezorobsco-cyber I updated this branch with the latest main and resolved the conflicts while preserving the storage migration coverage. The full escrow Rust test suite and formatting check pass. Please review and merge when ready.

@damilare0813

Copy link
Copy Markdown
Contributor Author

@afeezorobsco-cyber This branch now includes the latest main and is conflict-free. The full escrow Rust test suite and formatting check pass. Please review and merge when ready.

@github-actions

Copy link
Copy Markdown

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

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

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

SDK bindings match contract WASM

sdk/src/generated/contract-client.ts is out of date.

sdk/src/generated/contract-client.ts doesn't match the contract any more, because main has changed the contract since your branch was created. Regenerate the bindings against the latest main and commit them:

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 runs the same check locally.)

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

@damilare0813

Copy link
Copy Markdown
Contributor Author

@afeezorobsco-cyber I resolved the merge conflicts against the latest main, preserved this PR’s feature, regenerated the contract bindings, and updated the affected test snapshots. The escrow contract tests pass. Could you please review the update and merge when ready?

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

Copy link
Copy Markdown
Contributor

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

SDK bindings match contract WASM

sdk/src/generated/contract-client.ts is out of date.

sdk/src/generated/contract-client.ts doesn't match the contract any more, because main has changed the contract since your branch was created. Regenerate the bindings against the latest main and commit them:

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 runs the same check locally.)

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

Copy link
Copy Markdown

@damilare0813 This PR now has merge conflicts with main, most likely because #150 (feat(contract): add two-party releaser rotation) 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

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

@github-actions

Copy link
Copy Markdown

@damilare0813 This PR now has merge conflicts with main, most likely because #255 (feat(deploy): scripted, deterministic contract deployment with records) 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

@damilare0813 This PR now has merge conflicts with main, most likely because #258 (Feat/sdk lifecycle amendments 84) 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.

1 similar comment
@github-actions

Copy link
Copy Markdown

@damilare0813 This PR now has merge conflicts with main, most likely because #258 (Feat/sdk lifecycle amendments 84) 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

@damilare0813 This PR now has merge conflicts with main, most likely because #143 (feat(contract): add constrained M-of-N releaser account) 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

@damilare0813 This PR now has merge conflicts with main, most likely because #202 (feat(security): formal verification spike for invariants I1–I3) 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

@damilare0813 This PR now has merge conflicts with main, most likely because #211 (feat(security): audit-readiness package for the Phase E5 contract features) 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.

1 similar comment
@github-actions

Copy link
Copy Markdown

@damilare0813 This PR now has merge conflicts with main, most likely because #211 (feat(security): audit-readiness package for the Phase E5 contract features) 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

@damilare0813 This PR conflicts with main, so it can't be merged yet. Please rebase onto the latest main:

git fetch upstream
git rebase upstream/main
# fix the conflicts, then
git push --force-with-lease

If the conflict is in ROADMAP.md's changelog, move your entry into a changelog.d/ fragment instead of editing ROADMAP.md.

@github-actions

Copy link
Copy Markdown

@damilare0813 This PR now has merge conflicts with main, most likely because #262 (chore(sdk): refresh lockfile to clear axios/follow-redirects advisories) 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

@damilare0813 This PR now has merge conflicts with main, most likely because #210 (feat(ci): futurenet compatibility checks ahead of Stellar protocol upgrades) 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.

1 similar comment
@github-actions

Copy link
Copy Markdown

@damilare0813 This PR now has merge conflicts with main, most likely because #210 (feat(ci): futurenet compatibility checks ahead of Stellar protocol upgrades) 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

@damilare0813 This PR conflicts with main again after your latest push, so it can't be merged yet. Please rebase onto the latest main:

git fetch upstream
git rebase upstream/main
# fix the conflicts, then
git push --force-with-lease

If the conflict is in ROADMAP.md's changelog, move your entry into a changelog.d/ fragment instead of editing ROADMAP.md.

…DocForum#37)

Resolve the conflicts with origin/main (d74b961) and fix the failing
"SDK bindings match contract WASM" check:

- contracts/escrow/src/lib.rs: keep the tagged StoredEscrowData V1-V4
  layout next to main's pooled-escrow types. Every escrow read and write
  now goes through load_escrow/save_escrow (pooled create/contribute/
  claim_refund, rotate_releaser, top_up, refund and settle included), so
  no record is written in the untagged layout.
- Error code collision: main's InvalidReleaser keeps 24. The new
  UnsupportedStorageVersion moves to 35, the next free discriminant.
- sdk/src/generated/contract-client.ts: regenerated with stellar CLI
  28.1.0 from the release WASM. The only change against main is the new
  UnsupportedStorageVersion error. scripts/check-generated-bindings.sh
  passes.
- contracts/escrow/test_snapshots: regenerated by cargo test. A second
  run leaves them byte-identical.
- changelog.d/37-versioned-storage-layout.md: changelog fragment.

Validation: cargo test (all binaries, --test-threads=1 and default)
passes, cargo build --target wasm32v1-none --release passes,
scripts/check-resource-baseline.py passes, and the SDK typecheck, build
and test:offline pass.
The PR branch on damilare0813/docforum-escrow moved to 6ea5f1f after this
branch was fetched. The merge adds no file changes against this branch, so
the tree is unchanged. Recorded here so the push is a fast-forward and that
commit is not dropped.
@github-actions

Copy link
Copy Markdown

@damilare0813 This PR now has merge conflicts with main, most likely because #210 (feat(ci): futurenet compatibility checks ahead of Stellar protocol upgrades) 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.

@damilare0813

Copy link
Copy Markdown
Contributor Author

Note for maintainers: the PR body is stale. It describes a V3 layout and does not mention V4 or the merge with main's pooled-escrow types. cargo fmt --check fails on main's existing code (lib.rs, cancel.rs, pooled.rs, model.rs, malicious_token.rs). This PR's own storage_migration.rs is clean. The fork's workflow run needs maintainer approval.

@damilare0813

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest main (28ec877) — merged, not rebased commit-by-commit,
to keep the history of how the two conflicting changes were reconciled. Both
conflicts were in contracts/escrow/src/lib.rs (direct DataKey::Escrow/
DataKey::Status writes in main's pooled-escrow and status-key code vs this
branch's save_escrow/save_status helpers) and in ARCHITECTURE_ESSENTIALS.md
(two unrelated paragraphs added next to each other). Resolved by routing every
write site through the versioned-storage helpers, so pooled escrows and the
status key both get the tagged V4 layout — covered by a new
pooled_escrow_body_is_written_as_tagged_v4 test and an updated
legacy_record_without_status_key_reports_status_from_the_escrow_body one.

No ROADMAP.md changelog edit was needed — the entry already lived in
changelog.d/37-versioned-storage-layout.md from before, and I updated that
fragment in place to mention the pooled-escrow and status-key interaction.
ROADMAP.md itself is untouched from main; there's no existing checklist
line for #37 to tick.

While I was in there I also fixed docs/adr/0008, which still described the
pre-main-merge V3/three-layout design — it now matches the current V4 scheme.

Regenerated SDK bindings with Stellar CLI 28.1.0 (no diff beyond the one new
error variant already in this PR). cargo test is green with snapshots
updated; a repeat run leaves the tree clean. cargo fmt --check still fails,
but only on lines that are byte-identical to main's own copies
(benches/resource_profile.rs and a few lines in src/lib.rs/tests) — this
PR doesn't introduce any new formatting diff, so I left those alone pending a
separate fmt pass on main. Full details and validation in the updated PR
description.

@damilare0813

Copy link
Copy Markdown
Contributor Author

@afeezorobsco-cyber this is ready for a look whenever you have a moment.

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

Copy link
Copy Markdown
Contributor

@damilare0813 CI is failing at Resource cost baseline:

python3 scripts/check-resource-baseline.py
get_status exceeds source-size baseline

Your change makes get_status larger than the recorded baseline. If that growth is intended, update the baseline with the script's update mode (see scripts/check-resource-baseline.py) and explain the increase in the PR. Otherwise slim the function down. Then push.

@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

@damilare0813 This PR now has merge conflicts with main, most likely because #209 (feat(contract): optional protocol fee taken at release (recipient and…) 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.

@zeemscript

Copy link
Copy Markdown

@afeezorobsco-cyber I reduced get_status below the resource source-size budget and verified the resource baseline plus all 7 storage migration tests locally. The updated head passes the malware scan. GitHub still reports a merge conflict against current main; it needs conflict resolution before merge.

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@damilare0813 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/37-phase-e5-version-escrow-storage-and-migr.md:

    bump: minor
    ---
    Issue #37: 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. Switch your new Error codes to provisional ones (issue number × 100 + n). This branch adds UnsupportedStorageVersion = 35; use UnsupportedStorageVersion = 3700. The fold assigns the final numbers. Don't renumber existing codes.

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

# Conflicts:
#	contracts/escrow/src/lib.rs
#	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
#	sdk/src/generated/contract-client.ts
@damilare0813

Copy link
Copy Markdown
Contributor Author

Synced this branch with current main and resolved the merge conflict. Kept CONTRACT_VERSION at 2.3.0, added the required issue #37 minor fragment and provisional UnsupportedStorageVersion code 3700, and migrated legacy funded records to V5 while seeding liability accounting on first rewrite. Full Rust tests, the contract-change check, and generated-binding check pass. GitHub reports mergeable=true; Malware scan is still pending. @afeezorobsco-cyber, please recheck when convenient.

@github-actions

Copy link
Copy Markdown

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-rebase Has merge conflicts with main; the author needs to rebase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Phase E5] Versioned storage layout and a migration strategy for EscrowData

3 participants