A private asset is the ordinary PCASH note format under one hidden nonzero asset ID. Its immutable descriptor permits one fixed issuance; after that, the protocol allows only owner-authorized transfer, split, merge, custody, and voluntary burn.
For youRead this if you want the asset model, its proof paths, and its hard limits without circuit internals.
Before you startThe payment article's ideas—notes, nullifiers, installed account rules, and one CHONK proof—are reused here.
Every note body commits an owner, an asset ID, and an amount. Asset ID zero means native PCASH. A nonzero ID names one standard fungible instance. The ID is inside the private proof rather than a public transaction field, so the network does not expose which asset moved.
There is no registry that assigns IDs or symbols. Anyone with the descriptor can recompute the same identity; wallets and catalogs decide which human name and metadata to attach to it. Changing the salt, metadata commitment, initial supply, or issuance-secret commitment creates a different asset.
View the source behind this explanationsdk/src/protocol/asset.ts:110
Private protocol paths share one public wire
Note-only movement, credit-capable movement, fee sponsorship, and issuance need different private logic, but observers should not receive a mode bit that classifies them. Each path ends with the same twenty-field private-value statement and one proof:
- The note-only direct kernel handles transfer and burn when one authenticated account owns every real note input.
- The credit-capable direct kernel lets the same user account add available credit to an action with zero through three owned notes.
- The native-fee-payer kernel adds one different account in the narrow role of paying the public PCASH fee.
- The issuance kernel creates the original supply with no fee.
- The funded-issuance kernel preserves the same issuance law while a separate authenticated account pays the fee.
The selected kernel, installed applications, accounts, input classes, amounts, and nonzero asset ID stay inside CHONK. The finalizer does not merely accept a label: each kernel proves its complete slot grammar, ownership, conservation, and application statements.
View the source behind this explanationcircuits/stacks/private_value/finalize/src/main.nr:12
Issuance happens once
- Create identityCommit fixed supply and secretThe descriptor determines one asset ID.
- Issue onceConsume the issuance nullifierOne to five outputs must sum to the original supply.
- MoveSpend ordinary private notesInputs equal outputs plus any voluntary burn.
- NeverNo later mint pathNo issuer freeze, clawback, or supply mutation exists.
The issuance proof opens the immutable configuration and private issuance secret, recomputes the asset ID, and consumes exactly one ASSET_ISSUANCE marker. It accepts no asset input and creates one to five asset outputs whose amounts sum exactly to the committed initial supply.
The secret derives one stable issuance nullifier scoped to this asset. Every valid-looking attempt to issue the same instance produces that same public nullifier, and the global spent set accepts it only once. Later actions must consume real asset notes. No other relation can create a nonzero-asset output without one.
View the source behind this explanationcircuits/stacks/asset_issuance/application/src/main.nr:65
Transfer and burn are ordinary note spending
There is no separate transfer application and no need to reopen the asset descriptor. The direct kernel opens the owner's notes, proves their membership and nullifiers, authenticates one exact installed account rule, constructs every output, and checks two integer conservation equations.
Asset value may become same-ID outputs or a private voluntary burn. Native PCASH may become native outputs or the public fee. An installed rule can impose commercial conditions—price, royalties, redemption, a schedule, or successor custody—but it authorizes the current owner's complete action. It does not modify the asset law.
A second account may pay only the native fee
The fee-payer role cannot contribute assets, choose asset recipients, make a native payment, or authorize the primary account's application.
The exception is intentionally narrow. The primary account must be a Contract Account, the fee payer a User Account, and the action must carry a nonzero asset, so there is no user-to-user sponsorship and no sponsored native-only transfer. All asset inputs and application markers belong to the primary account. All native inputs belong to the fee account. Native value can leave only as the declared fee and at most one change note owned by that same fee account.
The second account cannot contribute asset value, receive the asset as part of its role, redirect native change, make a third-party PCASH payment, or authorize the primary account's application. General multi-party exchange uses contract custody and sequential actions rather than this two-account path.
View the source behind this explanationcircuits/stacks/asset_transfer/with_native_fee_payer_kernel/src/main.nr:406
The fixed limits are the product boundary
- Real input slots
- Up to 4
- Output slots
- Up to 5
- Assets per action
- 1 nonzero ID
- Asset amount
- Less than 2¹²⁸ per note
- Initial supply
- At most 5 × (2¹²⁸ − 1)
- Aggregate and burn
- Less than 2¹³¹
A positive protocol fee is always paid in native PCASH. On the same-account path, available credit may cover the native side of an asset transfer or burn, including its fee, but it never enters the asset conservation equation and cannot create asset notes. The standard asset law has no later mint, freeze, pause, clawback, blacklist, transfer tax, receiver hook, mutable supply object, or public supply counter. A contract may control inventory while it owns the notes; its authority ends when those notes leave.