# Quickstart

> Deposit ETH, discover your note, and send a private transfer in five minutes.

This walkthrough takes a wallet that holds some Sepolia ETH from install to a first private transfer. Everything runs client-side against the Sepolia testnet.

## 1. Install

**SDK access:** The v2 SDK (`@privacy-pools-v2/sdk`) is not yet publicly available. Partners with early access are granted access to the `v2-monorepo` and consume the SDK from it as a workspace dependency. Reach out via X to request access: [@0xbowio](https://x.com/0xbowio).

## 2. Connect a wallet

The snippets below assume a viem wallet client and an HTTPS JSON-RPC endpoint. Any funded Sepolia account works:

```ts

const rpcUrl = process.env.RPC_URL;
if (!rpcUrl) throw new Error("set RPC_URL to an HTTPS JSON-RPC endpoint");

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const walletClient = createWalletClient({ account, chain: sepolia, transport: http(rpcUrl) });
const address = account.address;
```

In a browser app, `walletClient` comes from the user's connected wallet instead.

## 3. Derive your protocol keys

Privacy Pools v2 derives three private keys and one public viewing key from a single EIP-712 signature. You sign once per session; signing the same message again always re-derives the same keys.

```ts

const payload = buildSecretDerivationPayload(address);
const signature = await walletClient.signTypedData(payload);

const crypto = new CryptoService();
const keys = crypto.deriveKeysFromSignature({
    signature,
    signerAddress: address,
    addressHash: payload.message.addressHash,
    revocableKeyIndex: "0x0",
});
```

**Key derivation helper:** copy `buildSecretDerivationPayload` from `v2-monorepo/apps/sample/src/keystore/secretDerivationPayload.ts`, or build the same EIP-712 payload in your app. Fresh accounts use `revocableKeyIndex: "0x0"`. After key rotation, reuse the returned index.

## 4. Build a PoolSession

```ts

const session = await PoolSessionBuilder.fromConfig({
    chainId: 11155111,                               // Sepolia
    rpcUrl,
    ownerAddress: address,
    protocolKeys: { ...keys, revocableKeyIndex: "0x0" },
    aspUrl: "https://api-dev.0xbow.io",
    relayers: [
        {
            url: "https://relayer-v2-staging-149184580131.us-east1.run.app",
            name: "0xBow Relayer",
            chainId: 11155111,
            chainType: "evm",
            status: "active",
            address: "0x4Ba5fF376865b370790A56276C63e7984DCFf1f7",
            processorAddress: "0x762665Dc7aAeeA25DC1759AEBef1F61730497f6e",
        },
    ],
    walletInteractor: { type: "viem", walletClient },
})
    .withCircuitArtifacts(new FetchCircuitArtifacts("/circuits"))
    .create();
```

**Setup notes:**

1.  Proving runs client-side, so the session loads circuit artifacts over HTTP with `FetchCircuitArtifacts` pointed at wherever your app serves them (here `/circuits`). It is a sample-app helper rather than an SDK export, so copy `v2-monorepo/apps/sample-web/src/FetchCircuitArtifacts.ts` or supply your own `ICircuitArtifacts` loader (see [circuit artifacts](../sdk/circuit-artifacts)). The pre-compiled artifact set ships in `v2-monorepo/packages/circuits/build/`, so copy the circuits you serve from there.
2.  `address` is the relayer's signing wallet, while `processorAddress` is the [PrivacyPoolRelay](../protocol/contracts/privacy-pool-relay) contract the deployed relayer submits through. Proofs bind to the processor, so this value must match what the relayer actually uses.

## 5. Register on the keystore

Register before you spend. You can deposit first, but [transfer](../operations/transfer), [withdraw](../operations/withdraw), and [ragequit](../operations/ragequit) all prove keystore membership, so a deposit made by an unregistered wallet can be neither spent nor recovered until its owner registers (see [Accounts & keys](../operations/accounts-and-keys)).

```ts
if (!(await session.isKeystoreRegistered())) {
    await session.registerKeystore();   // two transactions, paid in Sepolia ETH
}
```

## 6. Deposit

```ts
const NATIVE_ETH = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
const receipt = await session.deposit({
    tokenId: NATIVE_ETH,
    value: "0x2386f26fc10000",             // 0.01 ETH in wei
});
console.log("deposit landed:", receipt.txHash);

// Wait for ASP approval (often within an hour, up to 7 days).
// Then sync your local note state from chain:
await session.discoverNotes();
const active = (await session.exportAccount()).notes
    .filter((n) => n.status === "ACTIVE");
console.log(`${active.length} spendable note(s)`);
```

When the deposit is [approved](../concepts/asp-attestation), the second log prints `1 spendable note(s)`. Until then it prints `0`: the [note](../concepts/notes) exists but is still `PENDING`.

## 7. Send a private transfer

The recipient is any address with a [registered viewing key](../operations/register-viewing-key); for a first run, a second account of your own works.

```ts
const recipientAddress = "0x...";          // a registered recipient
const myNotes = (await session.exportAccount()).notes
    .filter((n) => n.status === "ACTIVE");
const noteToSpend = myNotes[0];

const prepared = await session.prepareTransfer({
    inputCommitments: [noteToSpend.commitment],
    amount: "0x11c37937e08000",            // 0.005 ETH in wei
    tokenId: NATIVE_ETH,
    recipientDiscoveryData: { evmAddress: recipientAddress },
});

const result = await session.relayTransfer(prepared.relayOptions[0]);
console.log("transfer landed:", result.txReceipt.txHash);
```

A transaction hash on the final log means the transfer is on-chain.

**The transfer is complete.** The recipient's note is now in the pool. They can call `discoverNotes()` to find it ([discoverable mode](../concepts/discoverable-vs-oob)), or you can hand them the secret from `prepared.executeOptions.recipientPendingNotes[0].noteSecret` (out-of-band mode).

## Next steps

-   [Withdraw privately from the pool to a public address](../operations/withdraw).
-   Explore the other operations: [deposit](../operations/deposit), [transfer](../operations/transfer), [withdraw](../operations/withdraw), [payment requests](../operations/payment-requests), [ragequit](../operations/ragequit), and [managing notes](../operations/manage-notes).
-   Building an integration? See the [integration architecture guide](../guides/integration-architecture) and the [SDK reference](../sdk).
-   For common footguns and debugging tips, read [Failure modes](../dev-guide/failure-modes).
