Use fixed P2ID recipients for private PSWAP paybacks - #3918
partylikeits1983 wants to merge 21 commits into
Conversation
Separate the private-payback foundation from cancellation. Keep the storage and Rust/MASM changes, authenticated retained-note input support, fill and malformed-storage coverage, public creator reclaim, and updated benchmarks. Explicitly reject unsupported note actions in this layer. Private cancellation and its refund, fee-funding, and router-flow tests are provided by the dependent PSWAP cancellation branch.
33b722d to
2e678bd
Compare
Merge next at 701b6e1 to pick up the latest release workflow updates. Link the sealing changelog entry to PR #3923, align the seal procedure table row, clarify the sealed-flag offset documentation, and rename the mixed test helper section to HELPERS. Validation: 77 output-note, callback, and foreign-account tests passed; workspace formatting, targeted spelling, and diff checks passed.
Integrate PR #3923 and its latest next merge so PSWAP can compile and enforce immutable paybacks and remainders.
Propagate the output-note sealing dependency from PR #3918 so private cancellation can compile and enforce immutable refunds.
Use the output-note sealing implementation merged on next, including public attachments added before sealing. Preserve the fixed private recipient flow and verify authenticated reconstruction after issuer callbacks. Remove superseded callback tests and duplicate kernel changes, retain current release history, and refresh the four PSWAP fill benchmarks.
zeapoz
left a comment
There was a problem hiding this comment.
Looks good to me, left some suggestions!
PhilippGackstatter
left a comment
There was a problem hiding this comment.
Not a full review, just left a few comments/suggestions.
| pub fn execute( | ||
| &self, | ||
| consumer_account_id: AccountId, | ||
| account_fill_asset: Option<FungibleAsset>, | ||
| note_fill_asset: Option<FungibleAsset>, | ||
| ) -> Result<(Note, Option<PswapNote>), NoteError> { | ||
| ) -> Result<(RawOutputNote, Option<PswapNote>), NoteError> { |
There was a problem hiding this comment.
May be worth double-checking whether it's fine to return notes without the recipient here (i.e. RawOutputNote which contains private note as PartialNote), cc @VAIBHAVJINDAL3012.
If not, we would need to modify the PSwapPayback type to hold the full recipient, but I haven't though through all implications of that.
| let recipient = match self.storage.payback { | ||
| PswapPayback::Public { creator_account_id } => { | ||
| let serial = Word::new([ | ||
| self.serial_number[0] + ONE, | ||
| self.serial_number[1], | ||
| self.serial_number[2], | ||
| self.serial_number[3] + Felt::from(rounds - 1), | ||
| ]); | ||
| P2idNoteStorage::new(creator_account_id).into_recipient(serial) | ||
| }, | ||
| PswapPayback::Private { .. } => { | ||
| let recipient = private_recipient.ok_or_else(|| { | ||
| NoteError::other("private payback requires its recipient opening") | ||
| })?; | ||
| self.validate_private_payback_recipient(recipient)?; |
There was a problem hiding this comment.
Question: IIUC, for public notes we derive the correct serial from the PSWAP serial.
For private notes, validate_private_payback_recipient checks that the recipient, and therefore the serial number matches. Is that convenient? Would it be more convenient for callers to provide just P2idNoteStorage and the function computes the recipient, checks it matches, and constructs the note?
Co-authored-by: zeapoz <zeapo@pm.me>
Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
Private P2ID paybacks currently derive their serial number from the PSWAP serial number. For a public PSWAP, this lets observers reconstruct the paybacks and compute their nullifiers.
This implements the private-payback part of the updated proposal. Each order uses a fixed P2ID recipient commitment and discovery tag, with a fresh secret serial independent of the PSWAP serial. The recipient stays the same across fills and remainders; fillers need only its commitment. The owner retains the full recipient to reconstruct paybacks from their public fill attachments.
Public paybacks retain their existing recipient derivation and creator reclaim. Paybacks and remainders preserve the output sealing already merged in #3923 and #3927, including public attachments added by callbacks before sealing. Reconstruction must include the complete attachment list.
Private paybacks should first be committed on chain, then consumed as authenticated inputs. Unauthenticated consumption exposes the NoteId and links the payback to the consuming account. Discovery tags should not identify the target account.
Cancellation follows in #3911. Both PRs should land before releasing the new script. This changes the Rust APIs, private storage layout, and PSWAP script root.