Enter and exit liquidity with one asset
Compose a swap with a position change atomically, while keeping budgets, fees, and leftovers explicit.
A zap combines an ordinary swap with an ordinary liquidity operation. It provides a single transaction outcome while retaining both operations' fees, price impact, account validation, and lifecycle hooks. It is useful when an in-range or full-range position requires two assets but the user starts with one.
Zap in
The caller opens or selects an owned CLMM position and supplies ZapInArgs:
| Field | Purpose |
|---|---|
swap | ExactIn swap parameters, including the chosen conversion amount and minimum net output |
maximum_input | Total single-asset budget for conversion plus deposit |
minimum_liquidity | Positive lower bound on liquidity received |
liquidity_hook | Separate payload/account descriptors for add-liquidity callbacks |
swap_accounts_len | Boundary between swap remaining accounts and liquidity remaining accounts |
The core first swaps the caller-selected portion. It then computes affordable liquidity at the post-swap price, using the remaining input budget and only the actual net output produced by this operation.
For a 1,000 A budget, a caller might request a 480 A swap. The deposit can use at most the remaining A and the B just obtained. Preexisting B in the wallet does not silently increase the zap budget. Unused amounts and rounding leftovers remain in the wallet.
The correct conversion amount depends on price, range, liquidity, fees, and price impact. There is no optimal-split planner in this instruction. Simulate and quote the composed operation rather than assuming that swapping 50% is optimal.
Zap out
zap_out removes a negative liquidity delta, then swaps the withdrawn principal of one asset into the other. With a_to_b = true, the final desired asset is B:
final B = B principal withdrawn + net B received from swapping withdrawn Aminimum_output protects this aggregate output. Removal limits and the swap price limit are also enforced. If the conversion cannot consume all withdrawn input, the zap fails instead of claiming a one-asset exit with hidden leftovers.
The zap does not spend preexisting wallet balances or collect unclaimed LP fees. Collect position fees separately. Removing the pool's last usable liquidity can leave no liquidity for the conversion, so a full exit through the same market is not universally possible.
All relevant callbacks still run
flowchart LR BeforeSwap --> Swap --> AfterSwap AfterSwap --> BeforeAddLiquidity --> AddLiquidity --> AfterAddLiquidity
A zap in runs swap callbacks when a nonzero conversion is requested, then add-liquidity callbacks. A zap out runs remove-liquidity callbacks and then swap callbacks when there is input to convert. Supply account descriptors separately for each leg; the hook does not gain arbitrary access to the wallet because the operations were combined.
A denied callback, failed minimum, token error, or CU exhaustion rolls back every leg atomically. A successful first leg in a simulation is not enough to claim success for the whole zap.
Current boundaries
Zaps target CLMM mode, including graduated curves. They are local program composition; they are not automatic compounding, a strategy vault, or a multi-venue route optimizer. Full-range liquidity still economically needs both assets at an interior price—the zap obtains the second asset through a swap.
Source: programs/grapl-amm/src/instructions/zaps/. See status for verification and instructions for the entrypoint surface.