Skip to content

Separate out fee application into own typestate#881

Merged
spacebear21 merged 3 commits intopayjoin:masterfrom
arminsabouri:seperate-fee-application-typestate
Jul 18, 2025
Merged

Separate out fee application into own typestate#881
spacebear21 merged 3 commits intopayjoin:masterfrom
arminsabouri:seperate-fee-application-typestate

Conversation

@arminsabouri
Copy link
Collaborator

@arminsabouri arminsabouri commented Jul 15, 2025

This commit refactors fee application on the receiver side by moving
it out of the ProvisionalProposal typestate into a dedicated
WantsFeeRange typestate, as outlined in #870

It also removes the receiver_inputs field from
ProvisionalProposal, since it was solely used during fee computation
and is no longer needed in this state.

@arminsabouri arminsabouri changed the title WIP - seperate out fee application into own typestate WIP - separate out fee application into own typestate Jul 15, 2025
@arminsabouri arminsabouri force-pushed the seperate-fee-application-typestate branch 2 times, most recently from 58255be to 9861a58 Compare July 15, 2025 19:32
@arminsabouri arminsabouri changed the title WIP - separate out fee application into own typestate Separate out fee application into own typestate Jul 15, 2025
@coveralls
Copy link
Collaborator

coveralls commented Jul 15, 2025

Pull Request Test Coverage Report for Build 16326869862

Details

  • 104 of 110 (94.55%) changed or added relevant lines in 6 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.03%) to 85.8%

Changes Missing Coverage Covered Lines Changed/Added Lines %
payjoin-cli/src/app/v2/mod.rs 10 12 83.33%
payjoin/src/core/receive/v2/mod.rs 23 27 85.19%
Totals Coverage Status
Change from base Build 16298010662: 0.03%
Covered Lines: 7698
Relevant Lines: 8972

💛 - Coveralls

@arminsabouri arminsabouri marked this pull request as ready for review July 15, 2025 19:36
@arminsabouri
Copy link
Collaborator Author

FWIW I wanted to include an example of how we are using this in the Liana integration: payjoin/liana#8

@arminsabouri arminsabouri requested a review from spacebear21 July 15, 2025 19:42
Copy link
Collaborator

@spacebear21 spacebear21 left a comment

Choose a reason for hiding this comment

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

concept ACK, but the FFI parameter names should keep the fee rate unit, and the new typestate/method need docstrings (these should also be applied to the FFI layer).

I second Dan's suggestion in #870 to rename ProvisionalProposal to WantsSigner as well, but this can be done in a follow-up after we evaluate whether it should allow for multiple individual signature operations + a commitment method. I don't think that should block this PR since separating fee application solves a separate known problem and makes for a cleaner state machine regardless.

output_contribution_weight
}

pub fn commit_fee_range(
Copy link
Collaborator

Choose a reason for hiding this comment

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

The "commit" naming pattern refers to something that was contributed/applied to the existing typestate (e.g. contributed inputs/outputs) and "committing" it moves to the next typestate. Maybe apply_fee_range, with an explanatory docstring that it only applies a fee if the receiver contributions exceed the sender's additional fee, to match min_fee_rate, and not exceeding max_effective_fee_rate.

Copy link
Collaborator

@spacebear21 spacebear21 Jul 15, 2025

Choose a reason for hiding this comment

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

TBH the docstring from the inner apply_fee should probably just live on this method, since it's public whereas apply_fee is private.

Comment on lines 849 to 850
let mut finalized_psbt =
wallet_process_psbt(&self.payjoin_psbt).map_err(ReplyableError::Implementation)?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Was there a reason to move this to happen before the sender signatures get cleared? IIRC it had to happen in this order before to fix a bug in bitcoin-cli, though this specific bug has been fixed since. See #241

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not particularly. If it was moved that is my mistake.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed

Comment on lines 658 to 659
min_fee_rate: Option<u64>,
max_effective_fee_rate: Option<u64>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since the strong FeeRate type is lost in uniffi translation, we should specify the unit in the parameter names (e.g. min_fee_rate_sat_per_vb).

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 I had the same thought.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in the first commit

}

/// Psbt With fee contributions applied
pub fn psbt_with_fee_contributions(&self) -> Option<Arc<crate::Psbt>> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

What value does it provide to make this specific PSBT state accessible downstream? And is psbt_with_contributed_inputs still useful at all?

Copy link
Collaborator Author

@arminsabouri arminsabouri Jul 15, 2025

Choose a reason for hiding this comment

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

And is psbt_with_contributed_inputs still useful at all?

No I would recommend we either deprecate it or just remove it.

What value does it provide to make this specific PSBT state accessible downstream?

This is useful when the singer is not the entity that is progressing the state machine. In these wallet architectures the psbt that is "ready to be signed" will be made accessible when its requested. For a more concrete example please reference payjoin/liana#8. In this example, Lianad (backend service) will save the psbt with fee's applies in their psbt table. When the signer navigates to the their psbt page the backend will pull from this table and the user can sign.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

psbt_with_contributed_inputs is now removed

Copy link
Collaborator

Choose a reason for hiding this comment

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

It might carry more meaning to name this psbt_ready_for_signing?

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 agree

@arminsabouri arminsabouri force-pushed the seperate-fee-application-typestate branch from 9861a58 to 7776fa1 Compare July 15, 2025 22:07
@arminsabouri
Copy link
Collaborator Author

I second Dan's suggestion in #870 to rename ProvisionalProposal to WantsSigner as well, but this can be done in a follow-up after we evaluate whether it should allow for multiple individual signature operations + a commitment method. I don't think that should block this PR since separating fee application solves a separate known problem and makes for a cleaner state machine regardless.

I don't understand the rationale for this naming change or the new methods. rust-payjoin should less involved in signing operations and by extension application business logic. All rust-payjoin cares about from ProvisionalProposal to PayjoinProposal is that all the inputs belonging to the reciever are finalized. How it finalizes the inputs should be a application concern. Perhaps the naming should be WantsFinalizedInputs or WantsFinalizedProposal.

Copy link
Collaborator

@spacebear21 spacebear21 left a comment

Choose a reason for hiding this comment

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

utACK with a couple of naming comments that imo would be best addressed in this PR.

}

/// Psbt With fee contributions applied
pub fn psbt_with_fee_contributions(&self) -> Option<Arc<crate::Psbt>> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

It might carry more meaning to name this psbt_ready_for_signing?

@@ -819,21 +843,19 @@ impl ProvisionalProposal {
///
/// Errors if the final effective fee rate exceeds `max_effective_fee_rate`.
pub fn finalize_proposal(
Copy link
Collaborator

Choose a reason for hiding this comment

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

I just noticed this docstring needs to be updated too since all the fee stuff is now handled in WantsFeeRange.

@arminsabouri arminsabouri force-pushed the seperate-fee-application-typestate branch from 7776fa1 to 5eef949 Compare July 16, 2025 17:59
This commit refactors fee application on the receiver side by moving
it out of the `ProvisionalProposal` typestate into a dedicated
`WantsFeeRange` typestate, as outlined in payjoin#870

It also removes the `receiver_inputs` field from
`ProvisionalProposal`, since it was solely used during fee computation
and is no longer needed in this state.
This method was originally exposed to provide signers access to the PSBT
they are expected to sign. However, that PSBT excludes the receiver's
fee contributions. It has therefore been replaced by
`psbt_with_fee_contributions`.
@arminsabouri arminsabouri force-pushed the seperate-fee-application-typestate branch from 5eef949 to 3dcea20 Compare July 16, 2025 18:03
Copy link
Collaborator

@spacebear21 spacebear21 left a comment

Choose a reason for hiding this comment

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

re-ACK 3dcea20

@spacebear21 spacebear21 merged commit 16c13d6 into payjoin:master Jul 18, 2025
15 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.

3 participants