Skip to main content
Shield Swap does not debit a public wallet balance at the start of a user swap. The swap and swap_multi_hop functions consume an input token record and ask that token program to transfer the requested amount into the AMM’s public custody. Order construction must include record selection, spent-state checks, and change-record tracking.

Outcome

You are ready to build a swap when:
  • one record from the exact input token program is reserved for the attempt
  • the record is owned by the signer, unspent, and large enough for amount_in
  • the public amount satisfies the pool’s scale requirement
  • the client can serialize the complete record without dropping private fields
  • the client is prepared to discover and store any change record returned by the input transfer

Before you start

Confirm the concrete input record program, AMM token program, signer, target base-unit amount, asset kind, and current record commitments. A symbol or display name is not sufficient proof that a record belongs to the required program.

Record requirements

The selected record must satisfy all of the following:
  • It was created by the concrete input token program used by the pool.
  • It is owned by the account signing the swap.
  • It has not already been spent.
  • Its private amount is at least amount_in.
  • Its _nonce and _version match the on-chain commitment.
  • The wallet can serialize it in the format expected by the SDK or CLI.
The selected record must originate from the exact input token program. Wrapper records with matching symbols or decimals remain distinct assets.

Amounts are raw token units

amount_in uses the AMM token program’s native base units. The core contract performs no decimal normalization. For tokens with at most nine decimals, the scale is 1. For a token with more than nine decimals:
The raw input must be an exact multiple of scale. A record may contain a larger amount, but the public amount_in itself must satisfy this no-dust requirement. Review Native token amounts before building amount controls for mixed-decimal markets.

Acquiring a record

A wallet can use a record already in its local record store or call the input token program’s public-to-private transfer path to create one:
  1. Determine the concrete token program.
  2. Call transfer_public_to_private for the signer.
  3. Wait for acceptance.
  4. Locate the returned record output.
  5. Decrypt it with the signer’s key when needed.
  6. Preserve the complete record plaintext for later spending.
The token program performs this conversion. It neither deposits funds into the AMM nor establishes a pool position. Production wallets should prefer an existing spendable record when possible. Repeated public-to-private conversion adds latency, fees, and a public funding event before the swap.

Preserve record version and nonce

A token record includes private owner and amount fields plus public commitment metadata. The current helper preserves _version when it is present and defaults to version 1 only when parsing an older form. Dropping _version can make the wallet derive a different commitment and cause a Commitment does not exist failure. Do not rebuild a record from owner and amount alone. The record _nonce is unrelated to:
  • The public swap nonce used in swap_id
  • The counter used to derive a blinding factor
  • The private blinding factor itself
Keep these values in separate typed fields in wallet storage.

Selecting among records

The contract consumes one dynamic input record. It does not combine several small records inside swap. A practical selector should:
  1. Filter by concrete token program or dynamic record identifier.
  2. Exclude records already marked spent or pending.
  3. Exclude records owned by a different signer.
  4. Choose a record whose amount covers amount_in.
  5. Prefer the smallest sufficient record when that reduces change-management cost.
  6. Reserve the record locally before transaction construction.
If no one record is large enough, acquire or construct a larger record through the token program before submitting the swap. Do not pass multiple records or assume the AMM will consolidate them.

Change record behavior

The AMM requests an exact private-to-public transfer of amount_in. If the input record contains more, the token program returns a change record as a transition output. The change record is not the same as an unfilled swap refund: A user can receive both. The wallet must discover and store the input change immediately, then claim the AMM refund after finalize.

Record state machine

Use at least four local states:
  • available: confirmed unspent and eligible for selection
  • reserved: assigned to a transaction that has not reached a terminal status
  • spent: consumed by an accepted transaction
  • unknown: transaction outcome or record spend status cannot yet be confirmed
Do not return an unknown record to the available pool. Query transaction status and record commitment state first. When a swap is accepted, atomically update the local store with the consumed record, any change record, the swap_id, and the pending claim. Local crashes between those writes are a common cause of apparently missing funds.

Token metadata and record authority

The off-chain API supplies display metadata such as symbol, decimals, and wrapper program. Record spent state comes from chain data, token eligibility from contract mappings, and market approval from operator policy. Keep these layers separate:
  1. Off-chain token metadata
  2. Concrete token-program record identity
  3. On-chain decimal registration
  4. On-chain pool-creation allowlisting
  5. Pool, token, pair, and global pause state
  6. Operator compliance policy and asset review
The seed script is operator tooling. It defaults to a production API endpoint and writes unless dry-run mode is selected. Wallet record handling and compliance controls are separate.

Confidentiality considerations

Token records keep their plaintext confidential from ordinary public observers, but the swap exposes amount_in, pool, direction, price limit, minimum output, token identifiers, and timing as public data. Wallets should still protect:
  • Decrypted record plaintext
  • Private keys and view keys
  • Blinding factors and derivation counters
  • Local links between records, swap identifiers, and user profiles
  • Compliance record exports received through an authorized disclosure process
Avoid logging full record plaintext. Error messages should identify a local record by a non-sensitive internal handle or commitment, not by owner and amount.

Pre-submit checklist

  • The concrete record token matches the pool input side.
  • The signer owns the record.
  • The record is confirmed unspent.
  • The record amount covers amount_in.
  • amount_in is an exact native base-unit integer within u128.
  • _nonce and _version are preserved.
  • The record is locally reserved.
  • Change-record discovery is enabled.
  • Blinding recovery material is persisted.
  • The quote and deadline were generated from recent state.
Continue with Single-hop swaps or Multi-hop swaps.