Notes Have No Standard Way To Declare Or Enforce Who May Consume Them
- Linguagem predominante
- Rust
- Estrelas
- 132
- Forks
- 167
- Merge médio
- 1d 23h
- PRs com merge (30d)
- 110
Descrição
Note scripts in the standards library fall into two groups with respect to who may consume them: notes that commit a target account and enforce it, and notes that are open to any consumer by design. Nothing in the code distinguishes either group from a note where the check is simply missing by omission. `p2id` and P2IDE are examples of the first group: they commit a target account identifier to note storage and assert it against the active account before doing anything else. `pswap` is an example of the second group: it has no target check in its fill path by design, since any account may consume it and receive the offered asset in exchange for the requested one, which is the entire point of a swap note.
Two already-reported issues show what happens when a note falls into neither group: the note reads as though it should restrict its consumer, but nothing commits to or enforces one. [H-01](https://audits.openzeppelin.com/openzeppelin-miden/miden-01-07-smart-contract-diff-audit-nfts/issue/non-fungible-mint-notes-can-be-consumed-by-any-faucet-permanently-destroying-mint-entitlements-f47164f3) found that the generic MINT note script derives the minting faucet from whichever account consumes it, with no field anywhere in the note committing to which faucet was intended, so a MINT note addressed to one faucet can be consumed by a different one. [M-02](https://audits.openzeppelin.com/openzeppelin-miden/miden-01-07-smart-contract-diff-audit-nfts/issue/non-fungible-mint-notes-can-be-consumed-by-any-faucet-permanently-destroying-mint-entitlements-f47164f3) found that `owner_action`, `rbac_action`, `pause_action`, and `faucet_policy_action` record their managed account only in the note tag, which is documented as an unvalidated, best-effort filter, and none of the four scripts compares the active account against an intended target; the sender-based check each script performs establishes who may act on the consuming account, not whether that account is the one the note was written for. In both cases the gap is the same: the note never states, in a form the kernel or the script can check, which account it is for.
The burn path illustrates that the underlying property can hold without ever being stated. `receive_and_burn` is safe against the equivalent substitution only because the asset it operates on already carries a faucet identity fixed at mint time, which `validate_origin` can check independently of who is currently executing; nothing in `receive_and_burn` itself declares that the note may only be consumed by its issuing faucet, and a future change to how burns are validated could remove that guarantee without touching anything that currently reads as a target check, because there is no such check to remove.
Consider defining a standard way for a note to state who may consume it, either as a committed value in note storage or as an attachment (mirroring the `NetworkAccountTarget` attachment already used by AggLayer note scripts, or the storage-based approach `p2id` already uses), and requiring every note script to either enforce it or explicitly opt out for notes that are open to any consumer by design, such as `pswap`. Consider going further and making this an enshrined property of notes at the protocol level rather than a per-script convention, so that omitting the check is a visible, structural choice rather than something that can only be discovered by reading each script's logic.
Guia de contribuição
Avaliação
Esta issue ainda não foi avaliada.