Skip to content

Conversation

@spacebear21
Copy link
Collaborator

This gives implementers the ability to manually fail or cancel a receiver Payjoin session. A user might cancel a session for any reason, or the wallet might fail it if e.g. it detects a double-spend or cannot proceed past a transient error.

Note that the unit tests for closed sessions will need to be reworked once #1132 is merged, since the expected_receiver_state should be an error.

I used Claude sonnet 4.5 (it's quite good) to write the generic methods and unit tests.

Pull Request Checklist

Please confirm the following before requesting review:

@coveralls
Copy link
Collaborator

coveralls commented Oct 1, 2025

Pull Request Test Coverage Report for Build 18177469540

Details

  • 56 of 56 (100.0%) changed or added relevant lines in 2 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.08%) to 84.648%

Totals Coverage Status
Change from base Build 18176477486: 0.08%
Covered Lines: 8756
Relevant Lines: 10344

💛 - Coveralls

This gives implementers the ability to manually fail or cancel a
receiver Payjoin session. A user might cancel a session for any reason,
or the wallet might fail it if e.g. it detects a double-spend or cannot
proceed past a transient error.
Copy link
Collaborator

@arminsabouri arminsabouri left a comment

Choose a reason for hiding this comment

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

CodeAck

///
/// This method allows implementations to terminate the payjoin session when
/// the user decides to cancel the operation interactively.
pub fn cancel<P>(self, persister: &P) -> Result<(), P::InternalStorageError>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you think cancel is simpler than just calling close() on the persister?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The difference is that cancel() (and fail()) ensures that a Closed event is added to the log before closing.

/// This method allows implementations to terminate the payjoin session when
/// they encounter errors that cannot be resolved, such as insufficient
/// funds or a double-spend detection.
pub fn fail<P>(self, persister: &P) -> Result<(), P::InternalStorageError>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we push a generic failure error reply? Otherwise the sender will be hanging until expiration.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes good point, we do need a way to communicate this (and probably cancel() too) back to the sender.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I started down an approach where they transition to HasReplyableError to enforce responding to the sender. However there is an outstanding issue in that it needs to differentiate between Cancel and Failure outcomes when replaying the event log, so I think GotReplyableError would need to carry this information somehow.

I'm not sure if we actually need to reply in case of Cancel, assuming the receiver would broadcast the fallback tx?

Copy link
Contributor

@DanGould DanGould Oct 3, 2025

Choose a reason for hiding this comment

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

Cancel sounds like the unavailable wellKnownError to me, even if broadcast is sufficient

Copy link
Contributor

Choose a reason for hiding this comment

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

The only reason I can think of for a receiver to do this would be if the receiver wanted to refuse a naive tx.

A better solution for this example would be having the receiver use req-pj

So for now letting it expire is fine.

@spacebear21 spacebear21 marked this pull request as draft October 2, 2025 20:51
@spacebear21 spacebear21 added this to the payjoin-1.0 milestone Oct 3, 2025
@benalleng
Copy link
Collaborator

benalleng commented Oct 3, 2025

I wanted to pose a question as to why we really need to have these 2 seperate instead of just having application devs use fail() OR cancel() and provide a reason instead of having both of these?

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.

5 participants