Skip to content

fix: cooperative close uses actual spent amount instead of voucher ceiling#191

Merged
brendanjryan merged 1 commit intomainfrom
fix/cooperative-close-spent-amount
Apr 8, 2026
Merged

fix: cooperative close uses actual spent amount instead of voucher ceiling#191
brendanjryan merged 1 commit intomainfrom
fix/cooperative-close-spent-amount

Conversation

@gakonst
Copy link
Copy Markdown
Contributor

@gakonst gakonst commented Apr 3, 2026

Problem

On cooperative close, the server required the close voucher's cumulativeAmount to be >= highest_voucher_amount (the pre-authorized reservation). This meant clients were charged the full reservation even when actual usage was much lower.

Reproduced with Dune MPP: A SELECT 1 query (88ms execution, 4 bytes result) was charged the full $4.00 reservation instead of actual compute cost.

Root Cause

handle_close() validated:

if cumulative_amount < channel.highest_voucher_amount { // ❌ rejects actual-spend closes

And unconditionally overwrote the voucher:

highest_voucher_amount: cumulative_amount, // ❌ always stomps

Fix

Ports the fix from mppx (wevm/mppx#196) and wallet (tempoxyz/wallet#349).

Now matches the mppx handleClose implementation exactly:
Session.ts#L837-L846

  1. Spent check: cumulative_amount >= channel.spent (must cover actual usage)
  2. Settled check: cumulative_amount > on_chain.settled (must exceed on-chain settled, strict)
  3. Store update only overwrites highest_voucher_amount when the close amount is actually higher, preserving the original voucher for settlement.

Testing

All 240 existing tests pass. The behavioral change only affects cooperative close when the client sends a voucher below the highest pre-authorized amount but above actual spend — previously rejected, now accepted.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

⚠️ Changelog not found.

A changelog entry is required before merging. We've generated a suggested changelog based on your changes:

Preview
---
mpp: patch
---

Fixed close voucher validation to check against the actual spent amount (instead of `highest_voucher_amount`) and on-chain settled/deposit values via a dedicated `validate_close_amount` function. Also fixed on-chain channel state updates to only replace the highest voucher when the new amount is strictly greater. Added comprehensive unit tests mirroring the mppx reference implementation.

Add changelog to commit this to your branch.

@brendanjryan brendanjryan force-pushed the fix/cooperative-close-spent-amount branch 3 times, most recently from 1341eeb to 86c0893 Compare April 7, 2026 23:11
…iling

On cooperative close, the server required the close voucher's
cumulativeAmount to be >= highest_voucher_amount (the pre-authorized
reservation). This meant clients were charged the full reservation
even when actual usage was much lower (e.g., $4 for a SELECT 1 query).

This ports the fix from mppx (wevm/mppx#196) and wallet
(tempoxyz/wallet#349):

1. The minimum close amount is now max(channel.spent, on_chain.settled)
   instead of highest_voucher_amount, allowing clients to close at
   actual usage cost.

2. The store update only overwrites highest_voucher_amount when the
   close amount is actually higher, preserving the original voucher
   for settlement if the close is at a lower (actual spent) amount.

Amp-Thread-ID: https://ampcode.com/threads/T-019d5503-2e85-70ff-81ed-b5093c920fd5
Co-authored-by: Amp <amp@ampcode.com>
@brendanjryan brendanjryan force-pushed the fix/cooperative-close-spent-amount branch from 86c0893 to 81f3ea0 Compare April 7, 2026 23:13
@brendanjryan brendanjryan merged commit 4ec4f12 into main Apr 8, 2026
7 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.

2 participants