From 42f6daf902c633e0cf202a865f036d54e551d813 Mon Sep 17 00:00:00 2001 From: onurinanc Date: Tue, 1 Sep 2026 15:20:16 +0300 Subject: [PATCH 1/2] docs(standards): document that PSWAP remainders drop the routing target --- CHANGELOG.md | 1 + .../asm/standards/notes/pswap.masm | 9 +++++++++ crates/miden-standards/src/note/pswap.rs | 19 ++++++++++++++++--- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28f13826f2..5c6f164116 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,7 @@ - Fixed the fungible and non-fungible MINT note scripts assuming their `exec` callers provide blank stack slot ([#3668](https://github.com/0xMiden/protocol/pull/3668)). - [BREAKING] Bounded the multisig approver set to 64 signers, enforced both by `ApproverSet::MAX_APPROVERS` at account creation and by `MAX_NUM_APPROVERS` in the `multisig` and `multisig_smart` `update_signers_and_threshold` procedures ([#3723](https://github.com/0xMiden/protocol/pull/3723)). - The PSWAP note script now rejects a `PswapAttachment` that does not consist of exactly one word, instead of letting the attachment write past the four locals of `get_current_depth` ([#3761](https://github.com/0xMiden/protocol/pull/3761)). +- Documented that a PSWAP remainder note carries the round's `PswapAttachment` as its only attachment, so a `NetworkAccountTarget` routes the note it is attached to and not the order's lineage ([#3762](https://github.com/0xMiden/protocol/pull/3762)). ## v0.16.0 (2026-08-17) diff --git a/crates/miden-standards/asm/standards/notes/pswap.masm b/crates/miden-standards/asm/standards/notes/pswap.masm index ec4bb446e2..bea4f40b43 100644 --- a/crates/miden-standards/asm/standards/notes/pswap.masm +++ b/crates/miden-standards/asm/standards/notes/pswap.masm @@ -349,6 +349,15 @@ end #! most significant element of the active note's serial number), creates the output #! note, sets the attachment, and adds the remaining offered asset. #! +#! The round's PswapAttachment is the remainder's only attachment: any other attachment of the +#! parent, a `NetworkAccountTarget` included, is intentionally dropped, so a routing target applies +#! to the note it is attached to and not to the order's lineage. Carrying it over would make every +#! remainder a network output note, which the consumer's auth component sponsors before paying the +#! transaction fee (see `fees::create_network_note_sponsorships`): the fill would have to provision +#! the target as a foreign account and fund its sponsorship note, and a consumer that is itself the +#! target could not fill at all, since the kernel forbids a foreign context against the native +#! account. +#! #! Inputs: [offered_faucet_suffix, offered_faucet_prefix, #! amt_payout, amt_offered, #! remaining_requested, note_type, tag] diff --git a/crates/miden-standards/src/note/pswap.rs b/crates/miden-standards/src/note/pswap.rs index 0074e820b8..2138064531 100644 --- a/crates/miden-standards/src/note/pswap.rs +++ b/crates/miden-standards/src/note/pswap.rs @@ -266,7 +266,9 @@ impl From for NoteAttachment { /// fill amounts via note_args) and in network transactions (where note_args default to /// `[0, 0, 0, 0]`, triggering a full fill). To route a PSWAP note to a network account, /// set the `attachment` to a [`NetworkAccountTarget`](crate::note::NetworkAccountTarget) -/// via the builder. +/// via the builder. The routing applies to that note alone: a partial fill replaces it with a +/// remainder carrying only the PSWAP lineage attachment, so the leftover order is no longer a +/// network note and has to be filled locally or reclaimed by its creator. /// /// Fills are priced against the note's initial offered asset. #[derive(Debug, Clone, bon::Builder)] @@ -394,8 +396,8 @@ impl PswapNote { /// For notes targeting a network account, this may contain a /// [`NetworkAccountTarget`](crate::note::NetworkAccountTarget) with scheme = 2. For a /// remainder PSWAP this contains the [`Self::PSWAP_ATTACHMENT_SCHEME`] word - /// `[amt_payout, order_id, depth, 0]`. For an original PSWAP (no prior fill), - /// this is typically empty. + /// `[amt_payout, order_id, depth, 0]` and never a routing target. For an original PSWAP (no + /// prior fill), this is typically empty. pub fn attachments(&self) -> Option<&NoteAttachment> { self.attachment.as_ref() } @@ -632,6 +634,9 @@ impl PswapNote { /// remainder. Both are required because the price formula uses floor division, so one isn't /// derivable from the other across rounds in general. /// + /// Like the note the script creates, the reconstructed remainder carries `attachment` as its + /// only attachment. + /// /// # Errors /// /// Returns an error if `attachment.depth() == 0` or if any amount is not a valid asset @@ -820,6 +825,14 @@ impl PswapNote { /// [`Self::PSWAP_ATTACHMENT_SCHEME`]. The remainder must carry this attachment so that /// when *it* is later consumed as a parent, `get_current_depth` reads the right scheme /// and increments depth correctly. + /// + /// It is also the remainder's only attachment: a + /// [`NetworkAccountTarget`](crate::note::NetworkAccountTarget) on this note is deliberately not + /// copied over, matching the on-chain script. Carrying it over would make every remainder a + /// network output note, which a fee-paying consumer must sponsor - the fill would have to + /// provision the target as a foreign account and fund its sponsorship note, and a consumer that + /// is itself the target could not fill at all, since the kernel forbids a foreign context + /// against the native account. fn create_remainder_pswap_note( &self, consumer_account_id: AccountId, From 4f818f9d4058116e13bcd6dfb7094a694fa1fe7d Mon Sep 17 00:00:00 2001 From: onurinanc Date: Tue, 1 Sep 2026 15:50:36 +0300 Subject: [PATCH 2/2] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c6f164116..eb0c93e5a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,7 +82,7 @@ - Fixed the fungible and non-fungible MINT note scripts assuming their `exec` callers provide blank stack slot ([#3668](https://github.com/0xMiden/protocol/pull/3668)). - [BREAKING] Bounded the multisig approver set to 64 signers, enforced both by `ApproverSet::MAX_APPROVERS` at account creation and by `MAX_NUM_APPROVERS` in the `multisig` and `multisig_smart` `update_signers_and_threshold` procedures ([#3723](https://github.com/0xMiden/protocol/pull/3723)). - The PSWAP note script now rejects a `PswapAttachment` that does not consist of exactly one word, instead of letting the attachment write past the four locals of `get_current_depth` ([#3761](https://github.com/0xMiden/protocol/pull/3761)). -- Documented that a PSWAP remainder note carries the round's `PswapAttachment` as its only attachment, so a `NetworkAccountTarget` routes the note it is attached to and not the order's lineage ([#3762](https://github.com/0xMiden/protocol/pull/3762)). +- Documented that a PSWAP remainder note carries the round's `PswapAttachment` as its only attachment ([#3791](https://github.com/0xMiden/protocol/pull/3791)). ## v0.16.0 (2026-08-17)