Skip to content

feat(escrow_manager): reclaim idle escrow via thaw and withdraw - #21

Merged
tmigone merged 12 commits into
mainfrom
tmigone/escrow-withdraw
Sep 22, 2026
Merged

tmigone merged 12 commits into
mainfrom
tmigone/escrow-withdraw

Conversation

@tmigone

@tmigone tmigone commented Sep 18, 2026 •

Copy link
Copy Markdown
Member

Overview

The manager only deposited, so balances were a high-water mark of past debt. It can now reclaim idle escrow to the payer wallet, behind withdraw_enabled (default false).

One action per receiver per cycle, first match wins:

target = next_balance(...)                           # calculate
effective = balance - thawing                    # what the contract's getBalance reports
floor     = target × (1 + withdraw_margin)

# for each account only one of the following ops, evaluated in this order:
previous thawing matured                                  → Withdraw
effective < target                                        → Deposit(target - effective)
not thawing and balance - floor ≥ min_withdraw_grt        → Thaw(balance - floor)
otherwise                                                 → Nothing

Approach

  • A running thaw is never resized. The contract cannot grow one without resetting its 28-day timer, so debt growth during a thaw is answered by a deposit — the full amount leaves at maturity and the deposit covers the gap.
  • adjustThaw and cancelThaw stay unused. These are new interfaces in the contract but for simplicity thaws only start from zero, so plain thaw suffices.
  • Maturity uses the latest block timestamp, not wall clock. Timestamps are non-decreasing, so planning can be late but never early, and early reverts the whole batch.

Configuration

  • withdraw_enabled — new, defaults to false. No action needed; set true to reclaim escrow.
  • withdraw_margin — new, defaults to 0.25. No action needed.
  • min_withdraw_grt — new, defaults to 500. No action needed.

Motivation

#18 measured the escrow at ~2.87M GRT against ~1M GRT of debt and noted the algorithm targets ~1.67x but has no way to withdraw. This closes that gap.

Cross-component

The escrow accounts query now selects totalAmountThawing and thawEndTimestamp — an upstream dependency on the network subgraph exposing both. The query fails if a deployed version lacks them. Not verified; confirm against the deployed subgraph before merging.

Risk assessment

  • blast_radius: protocol — thaws and withdrawals are on-chain state receivers observe on their own escrow accounts; the default keeps it off until deliberately enabled.
  • reviewer_effort: deep — the decision logic is small and tested, but its correctness rests on PaymentsEscrow semantics this repo only vendors an ABI for.
  • primary_concern — with no cancel path, a thaw's full amount leaves at maturity, so the compensating deposit must fit the payer allowance and the 10,000 GRT MAX_ADJUSTMENT cap.
  • irreversible — not the merge, which is deposit-only at the defaults, but the enablement: a thaw is a 28-day on-chain commitment that reverting the code does not cancel.

Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
@coveralls

coveralls commented Sep 18, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 35750383409

Coverage decreased (-2.0%) to 44.122%

Details

  • Coverage decreased (-2.0%) from the base build.
  • Patch coverage: 328 uncovered changes across 5 files (127 of 455 lines covered, 27.91%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
crates/bin/escrow_manager/src/main.rs 343 127 37.03%
crates/bin/escrow_manager/src/contracts.rs 72 0 0.0%
crates/bin/escrow_manager/src/metrics.rs 18 0 0.0%
crates/bin/escrow_manager/src/subgraphs.rs 16 0 0.0%
crates/bin/escrow_manager/src/config.rs 6 0 0.0%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 2586
Covered Lines: 1141
Line Coverage: 44.12%
Coverage Strength: 141.59 hits per line

💛 - Coveralls

@tmigone tmigone changed the title feat(escrow_manager): add withdraw functionality feat(escrow_manager): reclaim idle escrow via thaw and withdraw Sep 18, 2026
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Comment thread crates/bin/escrow_manager/src/config.rs Outdated
Signed-off-by: Tomás Migone <tomas@thegraph.foundation>
Comment thread crates/bin/escrow_manager/src/contracts.rs Outdated
Comment thread crates/bin/escrow_manager/src/main.rs Outdated
tmigone and others added 5 commits September 21, 2026 15:33
@tmigone
tmigone force-pushed the tmigone/escrow-withdraw branch from aac87b1 to 71c72d1 Compare September 21, 2026 18:34
@tmigone
tmigone requested review from Maikol and MoonBoi9001 and a balanced review from Copilot September 21, 2026 18:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Subgraph state correctness, collector scoping, and unbounded transaction batches can cause incorrect deposits or indefinitely failing reclamation.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 4 High severity · 1 Low severity

Open (5)
What changed in this PR

Adds opt-in escrow reclamation through thawing and withdrawal while preserving deposit-only defaults.

Changes:

  • Adds reclamation configuration and decision logic.
  • Adds contract operations, subgraph state, metrics, tests, and documentation.
  • Extends the Grafana dashboard with reclamation monitoring.
File Description
grafana/​escrow_manager.json Adds reclamation panels and layout.
crates/​bin/​escrow_manager/​src/​subgraphs.rs Queries thawing account state.
crates/​bin/​escrow_manager/​src/​metrics.rs Adds thaw and withdrawal metrics.
crates/​bin/​escrow_manager/​src/​main.rs Plans and executes reclamation actions.
crates/​bin/​escrow_manager/​src/​contracts.rs Implements thaw and withdrawal calls.
crates/​bin/​escrow_manager/​src/​config.rs Adds reclamation settings and defaults.
crates/​bin/​escrow_manager/​README.md Documents behavior, configuration, and metrics.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread crates/bin/escrow_manager/src/contracts.rs
Comment thread crates/bin/escrow_manager/src/contracts.rs
Comment thread crates/bin/escrow_manager/src/subgraphs.rs
Comment thread crates/bin/escrow_manager/src/subgraphs.rs
Comment thread grafana/escrow_manager.json
Signed-off-by: Tomás Migone <tomas@thegraph.foundation>
Signed-off-by: Tomás Migone <tomas@thegraph.foundation>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

It introduces irreversible protocol transactions with an unverified deployed-subgraph dependency, and the identified dashboard and operational-guidance issues remain unresolved.

Review effort: Balanced
Findings: None

Resolved since last review (5)

Maikol
Maikol previously approved these changes Sep 22, 2026
Signed-off-by: Tomás Migone <tomas@thegraph.foundation>
@tmigone
tmigone merged commit 1301e9a into main Sep 22, 2026
13 checks passed
@github-actions github-actions Bot mentioned this pull request Sep 22, 2026
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.

4 participants