mint creates a concentrated-liquidity position from token records. It writes public economic state and returns a PositionNFT record.
Minting does not import earlier pool fees. The contract initializes the position’s fee checkpoints at the current fee growth inside its chosen range.
Outcome
Minting is complete when the transaction is accepted, the public position row contains the expected range and liquidity, the returnedPositionNFT is stored, and both token change records are accounted for.
Prerequisites
Before minting:- Confirm the program deployment and checksum.
- Confirm the pool exists and is enabled.
- Confirm global, token, and pair pause controls permit entry.
- Verify the supplied token IDs match canonical pool token0 and token1.
- Read the current slot and tick spacing.
- Select aligned lower and upper ticks.
- Find current predecessor hints for boundaries that are not initialized.
- Select token records with enough unspent value.
- Obtain freezelist non-inclusion proofs for signer, position owner, and withdrawal address.
Inputs
The transition accepts:- A private nonce
- A token0 record
- A token1 record
- A private recipient address
- A private immutable withdrawal address
- A public
MintPositionRequest - Public token0 and token1 program IDs
- Three pairs of
MerkleProofvalues for signer, recipient, and withdrawal
token_id is public.
The investigator-owned MintComplianceRecord supports authorized review of the mint. It contains the token ID, token programs, nonce, request, caller, signer, position owner, and immutable withdrawal address. The request’s public fields remain visible.
Range validation
The contract requires:Native base-unit amounts
Desired and minimum amounts use each token’s native base units. The contract calculates the maximum liquidity supported by the desired amounts at the current Q128.128 square-root price. It then calculates actual base-unit amounts with explicit rounding and checks that:- Actual amount does not exceed desired amount.
- Actual amount meets the corresponding minimum.
- Any token required by the current price region has a nonzero amount.
desired - used excess to the new position’s public tokens_owed balance. A newly minted position can therefore begin with a nonzero owed balance.
Boundary initialization
Each boundary has:liquidity_gross- Signed
liquidity_net - Outside fee growth for both tokens
- Previous and next initialized-tick pointers
max_liquidity_per_tick.
New boundaries are inserted into the pool’s linked tick index using caller-supplied predecessor hints. Existing boundaries keep their current list links.
Fee checkpoint
After both ticks are updated, the contract derives current fee growth inside the range:fee_growth_inside0_last_x_128fee_growth_inside1_last_x_128
hi and lo as arbitrary-precision integers.
Read Q128.128 fee growth.
Pool active liquidity
If the current tick is inside the new range, the slot’s active liquidity increases immediately. If the position is out of range, only its boundary state changes. It will enter the active set when price later crosses the appropriate tick. The slot also tightens its cached nearest initialized-tick pointers if a new boundary is closer to the current tick.Outputs
A successful mint returns:- Public
token_id PositionNFTrecord- Token0 change record
- Token1 change record
- Investigator-owned
MintComplianceRecord
PositionNFT contains owner, immutable withdrawal address, token ID, token program IDs, pool, and tick range. It does not contain live liquidity or fee balances. Those remain in the public positions mapping.
Persist:
- Original transaction ID
- Program ID and checksum
- Pool key and token ID
- Returned
PositionNFTciphertext - Decrypted record metadata
- Returned change records
- Public position state after finalization
tokens_owed0 and tokens_owed1 against the desired and actual used amounts. Do not treat the token change records as a refund of AMM-held excess.
Common rejection causes
- Wrong token order
- Pool, token, pair, or global pause
- Invalid signer, recipient, or withdrawal freezelist proof
- Lower or upper tick not aligned to spacing
- Invalid or stale insertion hint
- Zero calculated liquidity
- Per-tick liquidity cap exceeded
- Minimum amounts above actual consumed amounts
- Reused nonce and request producing an existing token ID
- Spent or insufficient token record