Skip to main content
Version: 0.17 (unstable)

Standard Note Types

The miden-standards crate provides built-in note patterns for common asset transfer scenarios. These are pre-compiled note scripts you can use directly via the builder API in client code.

P2ID (Pay to ID)​

The most common pattern — a note that can only be consumed by a specific account. The note script checks that the consuming account's ID matches the target, then transfers all assets.

When to use​

Use P2ID for standard asset transfers where only the intended recipient should be able to consume the note. This is the most common note type.

P2ID notes use the typed P2idNote builder from miden_standards::note. The script is pre-compiled MASM; build the typed note and convert it into a protocol Note with .into().

How it works​

  1. Creator creates a P2ID note with the assets attached and the target account ID plus a two-felt salt in note storage
  2. Consumer's transaction processes the note — the script verifies the consuming account's ID matches the target
  3. If the IDs match, all assets transfer to the consuming account; otherwise proof generation fails

Note storage​

ItemTypeDescription
target_account_idAccountIdThe account allowed to consume this note
salt[Felt; 2]Salt included in the storage commitment; defaults to [0, 0]

The encoded storage always contains four felts: target suffix, target prefix, and the two salt elements. Omitting .salt(...) from the builder uses [0, 0]. Use the builder to obtain the current script root and storage layout together.

A uniformly random salt kept private prevents identifying the target by comparing storage commitments for candidate account IDs. The default zero salt does not provide this protection, and salt does not hide account-derived note tags. See the v0.17 P2ID implementation.

Builder API​

use miden_protocol::note::Note;
use miden_standards::note::P2idNote;

let note: Note = P2idNote::builder()
.sender(sender)
.target(target)
.assets(assets)
.note_type(note_type)
.generate_serial_number(rng)
.build()?
.into();
ParameterTypeDescription
senderAccountIdAccount sending the note
targetAccountIdThe only account that can consume this note
salt[Felt; 2]Optional builder setting for the storage salt; defaults to [0, 0]
assetsVec<Asset>Assets to attach to the note
note_typeNoteTypePublic or Private
attachment / attachmentsNoteAttachment / iteratorOptional auxiliary data
generate_serial_number&mut impl FeltRngGenerates the required serial number

P2IDE (Pay to ID with Expiration)​

P2IDE extends P2ID with optional timelock and reclaim conditions. A configured timelock prevents any account from consuming the note before the specified height. If reclaim is enabled, the configured reclaimer can also consume the note once reclaim_height has been reached and any configured timelock has expired; the target remains authorized.

When to use​

Use P2IDE when the sender wants the option to reclaim assets if the recipient doesn't consume the note within a time window.

P2IDE notes use the typed P2ideNote builder from miden_standards::note. Its reclaimer and block-height constraints are optional builder fields.

How it works​

  1. The sender creates a P2IDE note with the target account ID and optional timelock, reclaim height, and reclaimer
  2. If a timelock is configured, no account can consume the note before it expires
  3. The target can consume the note once the timelock condition is satisfied
  4. If reclaim is enabled, the reclaimer can also consume the note once reclaim_height has been reached and any configured timelock has expired; the sender is the default reclaimer
  5. All other consumption attempts fail (proof generation fails)

Note storage​

ItemTypeDescription
reclaimerAccountIdAccount allowed to reclaim; defaults to the sender
targetAccountIdAccount allowed to receive the note
reclaim_heightOption<BlockNumber>Block height after which the reclaimer can consume the note, subject to the timelock
timelock_heightOption<BlockNumber>Block height before which no account can consume the note

Builder API​

use miden_protocol::note::Note;
use miden_standards::note::P2ideNote;

let note: Note = P2ideNote::builder()
.sender(sender)
.target(target)
.reclaimer(reclaimer)
.reclaim_height(reclaim_height)
.timelock_height(timelock_height)
.assets(assets)
.note_type(note_type)
.generate_serial_number(rng)
.build()?
.into();
ParameterTypeDescription
senderAccountIdAccount sending the note
targetAccountIdThe account that can receive the note
reclaimerAccountIdOptional reclaiming account; defaults to sender
reclaim_heightBlockNumberOptional block height after which the reclaimer can consume the note, subject to the timelock
timelock_heightBlockNumberOptional block height before which no account can consume the note
assetsVec<Asset>Assets to attach to the note
note_typeNoteTypePublic or Private
attachment / attachmentsNoteAttachment / iteratorOptional auxiliary data
generate_serial_number&mut impl FeltRngGenerates the required serial number

SWAP (Atomic Exchange)​

SWAP enables atomic asset exchange. The creator offers one asset; any consumer who provides the requested asset in return can consume the note. The swap is atomic — both sides happen in a single transaction or neither does.

When to use​

Use SWAP for trustless atomic exchanges where two parties trade assets without intermediaries.

SWAP notes use the typed SwapNote builder from miden_standards::note. Read the expected payback details from the typed value before converting it into a protocol Note.

How it works​

  1. The creator creates a SWAP note containing the offered asset and storage describing the requested asset and payback configuration
  2. The consumer's transaction moves the requested asset from their vault into a P2ID payback note targeted at the creator
  3. The transaction moves the offered asset from the SWAP note into the consumer's vault
  4. The payback note creation and offered asset transfer happen atomically in the same transaction

Builder API​

use miden_protocol::note::Note;
use miden_standards::note::SwapNote;

let swap = SwapNote::builder()
.sender(sender)
.offered_asset(offered_asset)
.requested_asset(requested_asset)
.note_type(swap_note_type)
.payback_note_type(payback_note_type)
.generate_serial_number(rng)
.build()?;

let payback_note_details = swap.payback_note_details();
let note: Note = swap.into();
ParameterTypeDescription
senderAccountIdAccount that receives the payback P2ID note
offered_assetAssetAsset the note carries (what the consumer receives)
requested_assetAssetAsset the consumer must provide in return
swap_note_typeNoteTypePublic or Private for the SWAP note
attachment / attachmentsNoteAttachment / iteratorOptional auxiliary data for the SWAP note
payback_note_typeNoteTypePublic or Private for the P2ID payback note
generate_serial_number&mut impl FeltRngGenerates the required serial number

The builder returns a typed SwapNote. Call payback_note_details() before converting it into the Note to submit.

Attachments are optional. Use .attachment(value) or .attachments(values) only when needed; see note attachments for the underlying SDK API.

More note types​

For PSWAP, MINT, BURN, and other standard notes, see Standard Notes. For writing custom note scripts, see Note Scripts. For the transaction context and #[tx_script], see Transaction Context.