Skip to content

fix(core): keep pending rollback mint-backed#175

Open
Kelbie wants to merge 2 commits into
cashubtc:masterfrom
Kelbie:codex/offline-send-rollback
Open

fix(core): keep pending rollback mint-backed#175
Kelbie wants to merge 2 commits into
cashubtc:masterfrom
Kelbie:codex/offline-send-rollback

Conversation

@Kelbie
Copy link
Copy Markdown

@Kelbie Kelbie commented May 16, 2026

Summary

  • Keep rollback for pending send operations mint-backed, including exact-match sends where needsSwap === false.
  • Do not restore original input proofs locally once a send reaches pending, because Coco cannot know whether the bearer token has already been shared or spent.
  • Surface PendingSendRollbackError with Cannot roll back safely without mint connection. Token might have been spent. when pending reclaim cannot complete safely.
  • Keep rolling_back out of the public reclaim retry path for this PR; broader cancel-later/retry behavior is intentionally left for a future design.

Problem

A wallet can create an ecash token while offline when selected proofs exactly match the requested amount. The original PR tried to make offline cancellation local too, but maintainer feedback clarified that this is unsafe once the operation is pending: at that point the token might already have left the device or been redeemed, so rollback must go through the mint to avoid double-spend risk.

Summary of changes

  • Removed the exact-match pending rollback shortcut that restored input proofs locally.
  • Restored SendOpsApi.reclaim() to only accept pending operations.
  • Added PendingSendRollbackError, exported through the existing core model exports, to preserve the underlying cause while giving clients a clearer message.
  • Added focused tests proving exact-match pending rollback uses the mint-backed reclaim path and does not restore proofs locally.
  • Added .changeset/safe-pending-rollbacks.md for @cashu/coco-core.

Verification

  • bun test packages/core/test/unit/DefaultSendHandler.test.ts packages/core/test/unit/SendOperationService.test.ts packages/core/test/unit/SendOpsApi.test.ts
  • git diff --check
  • bun run --filter='@cashu/coco-core' typecheck still fails on existing integration-test setup noise: @cashu/coco-adapter-tests cannot be resolved and an integration-test @ts-expect-error is unused. No typecheck errors remain from this patch.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 16, 2026

🦋 Changeset detected

Latest commit: 6b56e77

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 7 packages
Name Type
@cashu/coco-core Patch
@cashu/coco-adapter-tests Patch
@cashu/coco-expo-sqlite Patch
@cashu/coco-indexeddb Patch
@cashu/coco-react Patch
@cashu/coco-sqlite-bun Patch
@cashu/coco-sqlite Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@Kelbie
Copy link
Copy Markdown
Author

Kelbie commented May 16, 2026

Full disclosure, this was fully vibed with Codex 5.5 High. I did verify this fixed my issue. I can now properly rollback while offline due to these changes. It also helped me clean up my previously corrupted rollbacks too. I was going to make an issue but since I had some working code I'd make a PR so you can have a better understanding of the issue I'm dealing with.

@Kelbie
Copy link
Copy Markdown
Author

Kelbie commented May 18, 2026

i think i might be assuming its always safe to rollback ecash sent offline which just isn't true. probably the correct thing to do is to just have proper error handling on my side...

@Egge21M
Copy link
Copy Markdown
Collaborator

Egge21M commented May 18, 2026

i think i might be assuming its always safe to rollback ecash sent offline which just isn't true. probably the correct thing to do is to just have proper error handling on my side...

I think this might be true. The issue is that as soon as SendOperation hits pending, Coco no longer knows whether the token has been sent out or not. Rolling back a pending operation safely requires a mint call, as we might run into double spending issues otherwise.

Even though it's not beautiful a "Can not roll back safely without mint connection. Token might have been spent" error on the client is the best way.

@Egge21M
Copy link
Copy Markdown
Collaborator

Egge21M commented May 18, 2026

@Kelbie do you want to continue working on this? I do think recovering pending offline is our of scope, but maybe you could pivot to one of the following:

  • keep exact-match pending rollback blocked offline;
  • possibly improve the error message;
  • keep or add tests proving exact-match pending sends do not restore proofs locally;
  • maybe leave retry support for rolling_back only where rollback recovery is actually safe.

@Kelbie
Copy link
Copy Markdown
Author

Kelbie commented May 18, 2026

I'll probably go about improving the error message for now.

I think the dream would be to have retry logic here, similar to "receive later" feature I've mentioned in an issue. It would be nice to have a "cancel later" so that it eventually rolls back when its safe without users having to be conscious of being online or offline.

I'll pivot and see what I can improve here. I won't do this retry logic yet but if you really like that idea I'm down to try to make that work.

@Kelbie Kelbie changed the title fix(core): rollback offline-created exact-match sends locally fix(core): keep pending rollback mint-backed May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants