> For the complete documentation index, see [llms.txt](https://zka-protocol.gitbook.io/zka-protocol-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://zka-protocol.gitbook.io/zka-protocol-docs/developer/building-zkap-frames.md).

# Building ZKAP Frames

A ZKAP Frame is the core object that replaces traditional blockchain transactions.\
Instead of sending a public, metadata-rich transaction, developers use the SDK to construct an **encrypted, zero-knowledge–validated frame** that can be submitted to the ZKAP Validator contract.

This file explains how to build a ZKAP Frame step-by-step:\
identity → payload → encryption → proof → frame assembly.

***

### 1. What is a ZKAP Frame?

A ZKAP Frame is a structured object containing:

* a zero-knowledge proof
* a commitment binding the payload
* encrypted payload (ciphertext)
* a nullifier (to prevent replay attacks)
* a session hash
* an expiry block

The final frame looks like this conceptually:

```
{
zk_proof: "0x...",
commitment_root: "0x...",
payload_ciphertext: "0x...",
nullifier: "0x...",
session_hash: "0x...",
expiry_block: 12345678
}
```

Every field is essential for validity and anonymity.

***

### 2. Prerequisites before building a frame

Before building a frame, you must have:

1. An ephemeral anonymous identity
2. A well-formed payload
3. A symmetric encryption key
4. Access to the ZK proof system
5. The expiry block for the request

These are typically created using the SDK.

***

### 3. Step 1 — Generate an Anonymous Identity

Identity is ephemeral and unlinkable.

Example (SDK function):

const id = generateIdentity();

This identity is used only inside the proof.

***

### 4. Step 2 — Create the Payload

A payload is a plain object representing the action.

Example:

```
const payload = {
action: "swap",
tokenIn: "USDC",
tokenOut: "ETH",
amount: "500",
minOut: "0.3",
expiry: 12345678
};
```

This data will be encrypted before being added to the frame.

***

### 5. Step 3 — Encrypt the Payload

Encryption ensures no one can read the payload except the destination application.

Example:

const ciphertext = await encryptPayload(payload, sessionKey);

The ciphertext hides all details, including:

* token types
* amounts
* action type
* routing logic
* strategy parameters

***

### 6. Step 4 — Generate the Zero-Knowledge Proof

The proof validates:

* payload structure
* identity correctness
* nullifier derivation
* expiry constraints
* commitment root consistency

Example (conceptual):

```
const proof = await generateProof({
identity: id,
payloadHash,
nonce,
expiry
});
```

The blockchain will verify this proof using the ZKAP Validator.

***

### 7. Step 5 — Build the Commitment Root

The commitment root binds the encrypted payload and expiry together.

commitment\_root = Hash(payload\_hash || expiry\_block)

This guarantees that the payload cannot be tampered with after proof generation.

***

### 8. Step 6 — Derive the Nullifier

The nullifier prevents replay attacks.

const nullifier = deriveNullifier(id, nonce);

A nullifier:

* reveals nothing about identity
* prevents replays
* is safe to publish

It’s the only persistent state stored by the validator.

***

### 9. Step 7 — Create the Session Hash

The session hash provides optional context for ephemeral flows.

const sessionHash = createSessionHash(id, payloadHash);

This makes correlation between actions impossible.

***

### 10. Step 8 — Assemble the ZKAP Frame

Now combine all components:

```
const frame = {
zk_proof: proof,
commitment_root,
payload_ciphertext: ciphertext,
nullifier,
session_hash: sessionHash,
expiry_block: payload.expiry
};
```

This frame is what gets submitted to the blockchain.

***

### 11. Step 9 — Submit the Frame

Once assembled, the frame can be submitted to the ZKAP Validator:

await submitFrame(frame);

If the proof verifies and nullifier is fresh,\
a **AnonymousAction** event is emitted.

***

### 12. Example Code (Putting It All Together)

Below is a simplified conceptual example:

```
import {
generateIdentity,
encryptPayload,
generateProof,
buildFrame,
submitFrame
} from "@zkap/sdk";

(async () => {
const id = generateIdentity();
const payload = { action: "swap", amount: 500, expiry: 12345678 };
const ciphertext = await encryptPayload(payload);
const proof = await generateProof({ identity: id, payload });
const frame = await buildFrame({ proof, ciphertext, id, payload });
await submitFrame(frame);
})();
```

The SDK abstracts many low-level details, making integration simple.


---

# 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://zka-protocol.gitbook.io/zka-protocol-docs/developer/building-zkap-frames.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.
