> For the complete documentation index, see [llms.txt](https://hinkal-team.gitbook.io/hinkal/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hinkal-team.gitbook.io/hinkal/technical-description/solana-program/typical-flow.md).

# Typical Flow

A private swap on Solana spans several Solana transactions because of message-size limits. The order below is what a relayer-driven flow looks like end-to-end.

#### 1. Off-chain (client)

* Build `CircomData` for the chosen dimensions tuple (e.g. `2×2×1` for `swap2`).
* Generate the Groth16 proof.
* Encrypt the new UTXO output(s).
* Build the CPI instruction list for the chosen router (Jupiter, Raydium, …) as a `Vec<SolanaInstructionData>`.
* Pick an `id: u32` to seed the staging PDAs, and a 32-byte `swapper_account_additional_seed` to derive a unique swapper PDA for this swap.

#### 2. Stage (relayer or signer, multiple transactions)

* `init_nullifier(nullifier)` for each spent nullifier whose PDA does not yet exist.
* `store_proof_part1(id, proof_a, proof_b, proof_c, public_signals_part1)`.
* `store_proof_part2(id, public_signals_part2)`.
* `store_encrypted_outputs(id, encrypted_outputs)`.
* `store_instructions(id, instructions)` (swap only).

The split is deterministic: the staging PDAs are derived from `(program, deployer, signer, id)` so the final instruction can find them by re-deriving the seeds.

#### 3. Submit (single transaction)

`swap2` (or `swap6`) is invoked with:

* `id` (matches staging PDAs).
* `swapper_account_additional_seed` (matches the proof's public signals).
* `in_nullifiers` (must equal the public signals).
* `relayer_fee`, `variable_rate`.
* `dimensions = 2×2×1` (or `2×6×1`).

`remaining_accounts` carries every program/account referenced by the staged `SolanaInstructionData` list.

#### 4. Verify (`process_proof_and_state`)

* Groth16 verification (`verify_proof`).
* `calldata_hash` recomputation across recipient, signer, encrypted outputs, fees, instructions, and remaining accounts.
* Merkle root membership check against the 100-root window.
* Nullifier validation + insertion.
* Commitment insertion (skipped for legs flagged `on_chain_creation`).
* Whitelisted-relayer check, stealth-address randomness check, mint binding check.

#### 5. Move funds (`swap_common` + `perform_swap`)

* Storage vault → swapper PDA: input liquidity transferred under vault seeds.
* `perform_swap` replays the staged CPI batch. Account index `255` is replaced with the swapper PDA and signed via `invoke_signed`.
* `swapped_amount = balance_after - balance_before` on the destination side.

#### 6. Settle

* `calculate_total_fee = relayer_fee + swapped_amount * variable_rate / 10_000`. Fee is paid to the signer.
* The remainder forms the output UTXO. `build_onchain_utxo`-style construction → `process_onchain_commitments_swap*` inserts the commitment and emits `NewCommitment` (with non-zero `on_chain_data`) via `emit_cpi!`.
* `validate_token_balance_diff` / `validate_sol_balance_diff` runs on both legs to enforce:

```
balance_after - balance_before == amount_change + utxo_amount
                                 (or just utxo_amount when on_chain_creation)
```

#### 7. Cleanup (optional)

* `close_nullifier(nullifier)` (relayer only) reclaims rent for any pre-initialized nullifier PDA whose proof never landed (so the staging cost is not wasted on aborted attempts).

***

`transact*` and `transfer*` follow the same shape minus the swapper PDA and CPI batch:

* `transact2` / `transact6` move funds between the signer's wallet and the storage vault.
* `transfer2` / `transfer6` move only the relayer fee out of the vault; the rest is a pure shielded-to-shielded rebalance.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://hinkal-team.gitbook.io/hinkal/technical-description/solana-program/typical-flow.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
